From e03fac219130df103f98f7c73cc1b787857ae3f4 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 11:49:29 +0100
Subject: [PATCH 01/35] Finish migration of Android source set.
---
build.gradle.kts | 2 ++
kostr-core/build.gradle.kts | 5 +++--
.../kotlin/ktnostr/android/ExampleInstrumentedTest.kt | 4 +++-
.../kotlin/ktnostr/android/ExampleUnitTest.kt | 1 +
4 files changed, 9 insertions(+), 3 deletions(-)
rename kostr-core/src/{androidTest => androidInstrumentedTest}/kotlin/ktnostr/android/ExampleInstrumentedTest.kt (80%)
diff --git a/build.gradle.kts b/build.gradle.kts
index 4cda21e..0b30cc8 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -14,6 +14,8 @@ plugins {
kotlin("multiplatform") version "2.0.20" apply false
id("com.android.library") version "8.2.2" apply false
id("org.jetbrains.kotlinx.atomicfu") version "0.25.0"
+ //id("org.jetbrains.kotlin.android") version "2.0.0" apply false
+ //id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" apply false
}
diff --git a/kostr-core/build.gradle.kts b/kostr-core/build.gradle.kts
index ac0eff4..94d1f87 100644
--- a/kostr-core/build.gradle.kts
+++ b/kostr-core/build.gradle.kts
@@ -159,13 +159,14 @@ kotlin {
}
}
+ androidInstrumentedTest.configure {
+ //dependsOn(commonJvmTest)
+ }
val androidUnitTest by getting {
dependsOn(commonJvmTest)
}
- androidUnitTest.dependencies {
- }
val baseJvmTest by getting {
diff --git a/kostr-core/src/androidTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt b/kostr-core/src/androidInstrumentedTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt
similarity index 80%
rename from kostr-core/src/androidTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt
rename to kostr-core/src/androidInstrumentedTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt
index ee78a43..0d4e001 100644
--- a/kostr-core/src/androidTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt
+++ b/kostr-core/src/androidInstrumentedTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt
@@ -15,8 +15,10 @@ import org.junit.runner.RunWith
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
+// val someProfile = AndroidClient()
+// someProfile.testProfile()
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("kt.nostr.kostr_android.test", appContext.packageName)
+ assertEquals("ktnostr.android.test", appContext.packageName)
}
}
\ No newline at end of file
diff --git a/kostr-core/src/androidUnitTest/kotlin/ktnostr/android/ExampleUnitTest.kt b/kostr-core/src/androidUnitTest/kotlin/ktnostr/android/ExampleUnitTest.kt
index 226398e..a1181db 100644
--- a/kostr-core/src/androidUnitTest/kotlin/ktnostr/android/ExampleUnitTest.kt
+++ b/kostr-core/src/androidUnitTest/kotlin/ktnostr/android/ExampleUnitTest.kt
@@ -11,6 +11,7 @@ import org.junit.Test
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
+// println("Decoded profile: ${someProfile.toString()}")
assertEquals(4, 2 + 2)
}
From 178175745b86aa80f99fc8ed9e993fef5ea5c7e8 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 11:51:21 +0100
Subject: [PATCH 02/35] Configure the default OkHttp engine with ping interval
support.
---
.../commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt b/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt
index a8d5fc2..53a814a 100644
--- a/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt
+++ b/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt
@@ -2,8 +2,13 @@ package ktnostr.net
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
+import okhttp3.OkHttpClient
+import java.util.concurrent.TimeUnit
internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) {
+ engine {
+ preconfigured = OkHttpClient.Builder().pingInterval(15, TimeUnit.SECONDS).build()
+ }
config(this)
}
\ No newline at end of file
From 4a47c764fd2408e1f7b1b7ca8efba60273dc6d9e Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 12:28:55 +0100
Subject: [PATCH 03/35] Expose function for making a single filter request.
---
.../kotlin/ktnostr/nostr/client/ClientMessage.kt | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/client/ClientMessage.kt b/kostr-core/src/commonMain/kotlin/ktnostr/nostr/client/ClientMessage.kt
index 5a403d1..81cbcf8 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/client/ClientMessage.kt
+++ b/kostr-core/src/commonMain/kotlin/ktnostr/nostr/client/ClientMessage.kt
@@ -111,6 +111,15 @@ open class RequestMessage(
SubscriptionId -> $subscriptionId
Filters -> $filters
""".trimIndent()
+
+ companion object {
+ fun singleFilterRequest(
+ subscriptionId: String = uuid4().bytes.decodeToString().substring(0, 5),
+ filter: NostrFilter
+ ): RequestMessage {
+ return RequestMessage(messageType = "REQ", subscriptionId, listOf(filter))
+ }
+ }
}
@Serializable(with = ClientMessage.MessageSerializer::class)
From ba0983c9d55482a81db17080b787c61e3c3db699 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 12:38:05 +0100
Subject: [PATCH 04/35] Use varargs for the different Filter builder functions.
---
.../kotlin/ktnostr/nostr/NostrFilter.kt | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrFilter.kt b/kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrFilter.kt
index dd3e99c..c101971 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrFilter.kt
+++ b/kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrFilter.kt
@@ -44,28 +44,28 @@ class NostrFilter private constructor(
private var until: Long? = null
private var limit: Int = 1
- fun idList(iDList: List? = null) = apply {
- listOfIds = iDList
+ fun idList(vararg iDList: String = emptyArray()) = apply {
+ listOfIds = if (iDList.isEmpty()) null else iDList.toList()
}
- fun authors(authorList: List? = null) = apply {
- authorsList = authorList
+ fun authors(vararg authorList: String = emptyArray()) = apply {
+ authorsList = if (authorList.isEmpty()) null else authorList.toList()
}
- fun kinds(kindList: List) = apply {
- listOfKinds = kindList
+ fun kinds(vararg kindList: Int) = apply {
+ listOfKinds = kindList.toList()
}
- fun eventTagList(listOfEventTags: List? = null) = apply {
- eventTagList = listOfEventTags
+ fun eventTagList(vararg listOfEventTags: String = emptyArray()) = apply {
+ eventTagList = if (listOfEventTags.isEmpty()) null else listOfEventTags.toList()
}
- fun pubkeyTagList(pubkeyList: List? = null) = apply {
- pubkeyTagList = pubkeyList
+ fun pubkeyTagList(vararg pubkeyList: String = emptyArray()) = apply {
+ pubkeyTagList = if (pubkeyList.isEmpty()) null else pubkeyList.toList()
}
- fun topics(listOfTopics: List? = null) = apply {
- topicList = listOfTopics
+ fun topics(vararg listOfTopics: String = emptyArray()) = apply {
+ topicList = if (listOfTopics.isEmpty()) null else listOfTopics.toList()
}
fun since(timeStamp: Long? = null) = apply {
From 72eb9fe970dfdbd2cd2f6034553fdac02682dbc1 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 13:00:37 +0100
Subject: [PATCH 05/35] Add Kind 1111(comment) to list of kinds. Update README
to show new API usage.
---
README.md | 22 ++++++++++++++-----
.../commonMain/kotlin/ktnostr/nostr/Event.kt | 6 ++++-
2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 709dac4..cd65797 100644
--- a/README.md
+++ b/README.md
@@ -107,15 +107,27 @@ val customPool = RelayPool(relays = customRelays)
In order to make a subscription request, you need to construct a `RequestMessage`.
And to do that, you need to pass in a subscriptionId(just a string), and a `NostrFilter`:
```kotlin
-val postsByFiatjafFilter = NostrFilter.newFilter()
- .kinds(listOf(EventKind.TEXT_NOTE.kind)) // <-- Looking for posts. Other kinds can be added
- .authors(listOf("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d")) // <-- The profiles for which we want to find the posts(as indicated by .kinds() above)
+val postsCommentsByFiatjafFilter = NostrFilter.newFilter()
+ .kinds(EventKind.TEXT_NOTE.kind, EventKind.COMMENT.kind) // <-- Looking for posts and comments. Other kinds can be added
+ .authors("3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d") // <-- The profiles for which we want to find the posts and comments(as indicated by .kinds() above)
.limit(20) // <-- Setting a limit is important, to avoid issues with relays
.build()
val myRequest = RequestMessage(
- subscriptionId = "fiatjaf_posts",
- filters = listOf(postsByFiatjafFilter)
+ subscriptionId = "fiatjaf_posts_and_comments",
+ filters = listOf(postsCommentsByFiatjafFilter)
+)
+```
+
+If you want to make a request with a single filter, you can do so with `RequestMessage.singleFilterRequest`.
+Using the same example above, we can rewrite it as:
+
+```kotlin
+val postsCommentsByFiatjafFilter = ... //Same as above
+
+val myRequest = RequestMessage.singleFilterRequest( // <- singleFilterRequest is called here.
+ subscriptionId = "fiatjaf_posts_and_comments",
+ filter = postsByFiatjafFilter
)
```
Now, you can use the `NostrService` to make the request, either using `request()` or `requestWithResult()`.
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Event.kt b/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Event.kt
index 1053d3d..86929c8 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Event.kt
+++ b/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Event.kt
@@ -141,6 +141,10 @@ enum class EventKind(val kind: Int) {
/**
* This is used for auth events constructed by the client.
*/
- AUTH(22242);
+ AUTH(22242),
+ /**
+ * This is used for comments on any posts other than Kind 1 posts(i.e, blogposts, shared file events,etc).
+ */
+ COMMENT(1111);
}
From 14422c1dae7aab722031787fce3f51111e6f9f56 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 13:48:59 +0100
Subject: [PATCH 06/35] Remove Ktor-OkHttp engine ping config, until we find a
reliable one.
---
.../commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt | 5 -----
1 file changed, 5 deletions(-)
diff --git a/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt b/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt
index 53a814a..a8d5fc2 100644
--- a/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt
+++ b/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt
@@ -2,13 +2,8 @@ package ktnostr.net
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
-import okhttp3.OkHttpClient
-import java.util.concurrent.TimeUnit
internal actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) {
- engine {
- preconfigured = OkHttpClient.Builder().pingInterval(15, TimeUnit.SECONDS).build()
- }
config(this)
}
\ No newline at end of file
From eb00315d4da50ebd7034c38deac39e30340f0d96 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 14:41:24 +0100
Subject: [PATCH 07/35] NostrService refactor: Remove questionable and useless
code. Move Eose and Relay error counts inside requestWithResult. Improve
message handling. Break should be called when we receive an EOSE. Add
stopService() API.
---
.../kotlin/ktnostr/net/NostrService.kt | 78 +++++++++++--------
1 file changed, 47 insertions(+), 31 deletions(-)
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt b/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt
index 9bf9d6d..954cfae 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt
+++ b/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt
@@ -20,8 +20,10 @@ import kotlin.coroutines.CoroutineContext
class NostrService(private val relayPool: RelayPool = RelayPool()): CoroutineScope {
- private val serviceDispatcher = Dispatchers.IO.limitedParallelism(relayPool.getRelays().size, name = "NostrServiceDispatcher")
- private val relayEoseCount = atomic(0)
+ private val serviceDispatcher = Dispatchers.IO.limitedParallelism(
+ relayPool.getRelays().size,
+ name = "NostrServiceDispatcher"
+ )
private val serviceMutex = Mutex()
private val client = httpClient {
@@ -58,7 +60,6 @@ class NostrService(private val relayPool: RelayPool = RelayPool()): CoroutineSco
}
}
}
- client.close()
}
suspend fun request(
@@ -79,20 +80,21 @@ class NostrService(private val relayPool: RelayPool = RelayPool()): CoroutineSco
// val requestJson = eventMapper.encodeToString(requestMessage)
//
// for (relay in relayPool.getRelays()) {
+// var webSocketSession: WebSocketSession? = null
// println("Coroutine Scope @ ${relay.relayURI}")
// try {
-// client.webSocket(urlString = relay.relayURI) {
-// send(requestJson)
+// webSocketSession = client.webSocketSession(urlString = relay.relayURI)
+// webSocketSession.send(requestJson)
//
-// for (frame in incoming) {
+// for (frame in webSocketSession.incoming) {
// val received = (frame as Frame.Text).readText()
// val receivedMessage = eventMapper.decodeFromString(received)
// onRelayMessage(relay, receivedMessage)
// }
-// }
+//
// } catch (e: kotlinx.io.IOException) {
// onRequestError(relay, e)
-// if (client.isActive) this.client.cancel()
+// if (webSocketSession?.isActive == true) webSocketSession.cancel()
// } catch (err: Exception) {
// onRequestError(relay, err)
// } catch (t: Throwable) {
@@ -122,7 +124,6 @@ class NostrService(private val relayPool: RelayPool = RelayPool()): CoroutineSco
}
} catch (e: kotlinx.io.IOException) {
onRequestError(relay, e)
- if (client.isActive) this.client.cancel()
} catch (err: Exception) {
onRequestError(relay, err)
} catch (t: Throwable) {
@@ -139,16 +140,24 @@ class NostrService(private val relayPool: RelayPool = RelayPool()): CoroutineSco
val relayAuthCache: MutableMap = mutableMapOf()
val jobs = mutableListOf()
val requestJson = eventMapper.encodeToString(requestMessage)
+ val relayErrorCount = atomic(0)
+ val relayEoseCount = atomic(0)
- for (endpoint in endpoints) ret@{
- println("Coroutine Scope @ ${endpoint.relayURI}")
- val job = launch {
+ for (endpoint in endpoints) {
+ val job = this.launch {
+ println(this.coroutineContext.toString())
try {
client.webSocket(endpoint.relayURI) {
send(requestJson)
for (frame in incoming) {
- if (frame is Frame.Text) {
+ if (frame is Frame.Close) {
+ println("Received a close frame with reason: ${frame.readReason()}")
+ }
+ else if (frame is Frame.Binary) {
+ println("Received binary data : ${frame.readBytes()}")
+ }
+ else if (frame is Frame.Text) {
val message = eventMapper.decodeFromString(frame.readText())
when (message) {
is RelayEventMessage -> {
@@ -179,47 +188,54 @@ class NostrService(private val relayPool: RelayPool = RelayPool()): CoroutineSco
}
is RelayEose -> {
- if (relayEoseCount.value == endpoints.size){
- client.close()
-// if (isActive) break
-// break
-
- } else {
- relayEoseCount.update { it + 1 }
- println("Relay EOSE received from ${endpoint.relayURI}")
- println(message)
- }
- println("***********--")
- println("**List count: ${endpoints.size}")
- println("**EOSE count: ${relayEoseCount.value}")
- println("************--")
+ relayEoseCount.update { it + 1 }
+ println("Relay EOSE received from ${endpoint.relayURI}")
+ println(message)
+ break
+
}
is CloseMessage -> {
relayEoseCount.update { it + 1 }
println("Closed by Relay ${endpoint.relayURI} with reason: ${message.errorMessage}")
+ this.close()
}
is RelayNotice -> {
println("Received a relay notice: $message")
}
}
- break
+
}
}
}
} catch (e: Exception) {
- println("Failed to connect to $endpoint: ${e.message}")
+ println("Failed to connect to ${endpoint.relayURI}: ${e.message}")
+ relayErrorCount.update { it + 1 }
}
}
jobs.add(job)
}
- jobs.forEach { it.join() }
- client.close()
+
+ jobs.forEach { job -> job.join() }
+ if (jobs.all { it.isCompleted }) {
+ println("EoseCount : ${relayEoseCount.value}")
+ println("RelayErrorCount: ${relayErrorCount.value}")
+// if (relayEoseCount.value + relayErrorCount.value == endpoints.size){
+// stopService()
+//
+// }
+ relayEoseCount.update { 0 }
+ relayErrorCount.update { 0 }
+ }
return results
}
+ fun stopService(){
+ if (this.isActive) this.serviceDispatcher.cancel()
+ }
+
}
From 81f87126e6e2f8aa85a799266a22b1730d8edd35 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 15:00:09 +0100
Subject: [PATCH 08/35] Add custom Ktor HTTP client support. Update and make
adjustments to README.
---
README.md | 14 +++++++++++++-
.../kotlin/ktnostr/net/NostrService.kt | 17 +++++++++++------
2 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index cd65797..e34c631 100644
--- a/README.md
+++ b/README.md
@@ -93,6 +93,16 @@ val clientService = NostrService(
//Without a custom pool(using the default pool)
val service = NostrService()
```
+You can also use a custom HTTP client for the `NostrService`, as long as it has Websocket support.
+```kotlin
+val myHttpClient = httpClient {
+ // custom configs(or not)
+}
+val service = NostrService(customClient = myHttpClient)
+```
+The current limitation is that the HTTP client needs to be Ktor-compatible, that is, you create a
+custom Ktor engine that uses you client underneath.
+
Note that if you need to do anything custom, such as using read-only relays,
you will need to setup the list of relays, then use them in the relay pool:
```kotlin
@@ -157,9 +167,11 @@ during its execution. The function however displays the errors using standard ou
//Using requestWithResult() ---
// - Assuming a suspending context:
val events = clientService.requestWithResult(myRequest)
+events.forEach { println(it.content) }
// OR, following with the request() example above:
appScope.launch {
- val events = clientService.requestWithResult(myRequest)
+ val events = clientService.requestWithResult(myRequest)
+ events.forEach { println(it.content) }
}
```
## License
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt b/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt
index 954cfae..1f767ba 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt
+++ b/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt
@@ -1,5 +1,6 @@
package ktnostr.net
+import io.ktor.client.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*
@@ -19,22 +20,26 @@ import ktnostr.nostr.relay.*
import kotlin.coroutines.CoroutineContext
-class NostrService(private val relayPool: RelayPool = RelayPool()): CoroutineScope {
+class NostrService(
+ private val relayPool: RelayPool = RelayPool(),
+ val customClient: HttpClient? = null
+): CoroutineScope {
private val serviceDispatcher = Dispatchers.IO.limitedParallelism(
relayPool.getRelays().size,
name = "NostrServiceDispatcher"
)
private val serviceMutex = Mutex()
- private val client = httpClient {
- install(WebSockets){
+ private val client = customClient
+ ?: httpClient {
+ install(WebSockets){
- }
+ }
- install(Logging){
+ install(Logging){
+ }
}
- }
override val coroutineContext: CoroutineContext
get() = serviceDispatcher
From ec4e4423991c465e202f7a0a2edc3a6977bef204 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 15:47:04 +0100
Subject: [PATCH 09/35] Re-enable Maven publish plugin.
---
kostr-core/build.gradle.kts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kostr-core/build.gradle.kts b/kostr-core/build.gradle.kts
index 94d1f87..f690366 100644
--- a/kostr-core/build.gradle.kts
+++ b/kostr-core/build.gradle.kts
@@ -16,7 +16,7 @@ plugins {
id("com.android.library")
kotlin("plugin.serialization")
-// `maven-publish`
+ `maven-publish`
}
@@ -26,6 +26,7 @@ kotlin {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
+// jvmToolchain(17)
apiVersion.set(KotlinVersion.KOTLIN_1_8)
languageVersion.set(KotlinVersion.KOTLIN_1_8)
}
From 14a0126da25e159553c0b985b32f68522ca204f5 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 16:20:54 +0100
Subject: [PATCH 10/35] Add config for Jitpack CI builds.
---
jitpack.yml | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 jitpack.yml
diff --git a/jitpack.yml b/jitpack.yml
new file mode 100644
index 0000000..efde7bf
--- /dev/null
+++ b/jitpack.yml
@@ -0,0 +1,2 @@
+jdk:
+ - openjdk17
From 5a2ff4308aa1a3a33f661c6d6223580ef01e7893 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Tue, 11 Feb 2025 23:42:23 +0100
Subject: [PATCH 11/35] Tests: Migrate to new APi definitions.
---
.../kotlin/ktnostr/nostr/NostrFilterTest.kt | 40 +++++++++----------
.../nostr/client/ClientMessageTests.kt | 20 +++++-----
2 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrFilterTest.kt b/kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrFilterTest.kt
index 271cc62..a5acb3b 100644
--- a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrFilterTest.kt
+++ b/kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrFilterTest.kt
@@ -35,11 +35,11 @@ class NostrFilterTest {
val currentTimestamp = 1653822739L
val previousTimestamp = currentTimestamp - 24 * 60 * 60
val filter = NostrFilter.newFilter()
- .idList(eventIdList)
- .authors(authorList)
- .kinds(listOfKinds)
- .eventTagList(referencedEventIds)
- .pubkeyTagList(referencedProfiles)
+ .idList(*eventIdList.toTypedArray())
+ .authors(*authorList.toTypedArray())
+ .kinds(*listOfKinds.toIntArray())
+ .eventTagList(*referencedEventIds.toTypedArray())
+ .pubkeyTagList(*referencedProfiles.toTypedArray())
.since(previousTimestamp)
.until(currentTimestamp)
.limit(maxEventLimit)
@@ -58,22 +58,22 @@ class NostrFilterTest {
@Test
fun `the timestamp for the filter is correctly generated`() {
val filter = NostrFilter.newFilter()
- .idList(eventIdList)
- .authors(authorList)
- .kinds(listOfKinds)
- .eventTagList(referencedEventIds)
- .pubkeyTagList(referencedProfiles)
+ .idList(*eventIdList.toTypedArray())
+ .authors(*authorList.toTypedArray())
+ .kinds(*listOfKinds.toIntArray())
+ .eventTagList(*referencedEventIds.toTypedArray())
+ .pubkeyTagList(*referencedProfiles.toTypedArray())
.since(lowerTimeLimit)
.until(upperTimeLimit)
.limit(maxEventLimit)
.build()
val cloneFilter = NostrFilter.newFilter()
- .idList(eventIdList)
- .authors(authorList)
- .kinds(listOfKinds)
- .eventTagList(referencedEventIds)
- .pubkeyTagList(referencedProfiles)
+ .idList(*eventIdList.toTypedArray())
+ .authors(*authorList.toTypedArray())
+ .kinds(*listOfKinds.toIntArray())
+ .eventTagList(*referencedEventIds.toTypedArray())
+ .pubkeyTagList(*referencedProfiles.toTypedArray())
.since(lowerTimeLimit)
.until(upperTimeLimit)
.limit(maxEventLimit)
@@ -94,11 +94,11 @@ class NostrFilterTest {
val currentTimestamp = 1653822739L
val previousTimestamp = currentTimestamp - 24 * 60 * 60
val textEventFilter = NostrFilter.newFilter()
- .idList(null)
- .authors(null)
- .kinds(listOf(EventKind.TEXT_NOTE.kind))
- .eventTagList(null)
- .pubkeyTagList(null)
+ .idList()
+ .authors()
+ .kinds(EventKind.TEXT_NOTE.kind)
+ .eventTagList()
+ .pubkeyTagList()
.since(previousTimestamp)
.until(currentTimestamp)
.limit(30)
diff --git a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/client/ClientMessageTests.kt b/kostr-core/src/commonTest/kotlin/ktnostr/nostr/client/ClientMessageTests.kt
index f48cc03..a920607 100644
--- a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/client/ClientMessageTests.kt
+++ b/kostr-core/src/commonTest/kotlin/ktnostr/nostr/client/ClientMessageTests.kt
@@ -61,22 +61,22 @@ class ClientMessageTests {
companion object {
private val filterOne = NostrFilter.newFilter()
- .idList(listOf("event_id_1", "event_id_2", "event_id_3"))
- .authors(listOf("author_pubkey_1", "author_pubkey_2"))
- .kinds(listOf(EventKind.TEXT_NOTE.kind))
- .eventTagList(listOf("ref_event_id_1", "ref_event_id_2"))
- .pubkeyTagList(listOf("ref_pubkey_1"))
+ .idList("event_id_1", "event_id_2", "event_id_3")
+ .authors("author_pubkey_1", "author_pubkey_2")
+ .kinds(EventKind.TEXT_NOTE.kind)
+ .eventTagList("ref_event_id_1", "ref_event_id_2")
+ .pubkeyTagList("ref_pubkey_1")
.since(1653822739L - 24 * 60 * 60)
.until(1653822739L)
.limit(25)
.build()
private val filterTwo = NostrFilter.newFilter()
- .idList(listOf("event_id_4", "event_id_5"))
- .authors(listOf("author_pubkey_3", "author_pubkey_4"))
- .kinds(listOf(EventKind.METADATA.kind, EventKind.RELAY_RECOMMENDATION.kind))
- .eventTagList(listOf("ref_event_id_3", "ref_event_id_4"))
- .pubkeyTagList(listOf("ref_pubkey_2", "ref_pubkey_3", "ref_pubkey_4"))
+ .idList("event_id_4", "event_id_5")
+ .authors("author_pubkey_3", "author_pubkey_4")
+ .kinds(EventKind.METADATA.kind, EventKind.RELAY_RECOMMENDATION.kind)
+ .eventTagList("ref_event_id_3", "ref_event_id_4")
+ .pubkeyTagList("ref_pubkey_2", "ref_pubkey_3", "ref_pubkey_4")
.since(1653822739L - 24 * 60 * 60)
.until(1653822739L)
.limit(10)
From 43c2d7a5e0805c6247f2daa4461d4a55d13371aa Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 12:13:19 +0100
Subject: [PATCH 12/35] Disable publish at the module level.
---
kostr-core/build.gradle.kts | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/kostr-core/build.gradle.kts b/kostr-core/build.gradle.kts
index f690366..94d1f87 100644
--- a/kostr-core/build.gradle.kts
+++ b/kostr-core/build.gradle.kts
@@ -16,7 +16,7 @@ plugins {
id("com.android.library")
kotlin("plugin.serialization")
- `maven-publish`
+// `maven-publish`
}
@@ -26,7 +26,6 @@ kotlin {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
-// jvmToolchain(17)
apiVersion.set(KotlinVersion.KOTLIN_1_8)
languageVersion.set(KotlinVersion.KOTLIN_1_8)
}
From b418944a6ef67a144ab274a411d49fb4ce509b73 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 13:42:57 +0100
Subject: [PATCH 13/35] Rename project to Ballast. Refactor accordingly.
---
{kostr-core => ballast-core}/.gitignore | 0
{kostr-core => ballast-core}/build.gradle.kts | 2 +-
.../ballast}/android/ExampleInstrumentedTest.kt | 2 +-
.../src/androidMain/AndroidManifest.xml | 0
.../kotlin/ballast}/android/ExampleUnitTest.kt | 2 +-
.../ballast}/crypto/CryptoProvider.apple.kt | 2 +-
.../kotlin/ballast}/net/HttpClient.apple.kt | 2 +-
.../ballast}/crypto/CryptoProvider.commonJvm.kt | 2 +-
.../kotlin/ballast}/net/HttpClient.commonJvm.kt | 2 +-
.../commonMain/kotlin/ballast}/DateTimeUtils.kt | 2 +-
.../kotlin/ballast}/crypto/CryptoProvider.kt | 2 +-
.../kotlin/ballast}/crypto/CryptoUtils.kt | 2 +-
.../commonMain/kotlin/ballast}/net/HttpClient.kt | 2 +-
.../kotlin/ballast}/net/NostrService.kt | 16 ++++++++--------
.../commonMain/kotlin/ballast}/nostr/Event.kt | 6 +++---
.../commonMain/kotlin/ballast}/nostr/EventExt.kt | 4 ++--
.../commonMain/kotlin/ballast}/nostr/Events.kt | 10 +++++-----
.../kotlin/ballast}/nostr/NostrErrors.kt | 2 +-
.../kotlin/ballast}/nostr/NostrFilter.kt | 2 +-
.../src/commonMain/kotlin/ballast}/nostr/Tag.kt | 2 +-
.../ballast}/nostr/client/ClientMessage.kt | 6 +++---
.../kotlin/ballast}/nostr/relay/Relay.kt | 2 +-
.../kotlin/ballast}/nostr/relay/RelayMessage.kt | 4 ++--
.../kotlin/ballast}/nostr/relay/RelayPool.kt | 4 ++--
.../kotlin/ballast}/crypto/CryptoUtilsTest.kt | 2 +-
.../kotlin/ballast}/nostr/EventTests.kt | 2 +-
.../kotlin/ballast}/nostr/NostrFilterTest.kt | 4 ++--
.../kotlin/ballast}/nostr/NostrTests.kt | 2 +-
.../ballast}/nostr/client/ClientMessageTests.kt | 6 +++---
.../ballast}/nostr/relay/RelayMessageTests.kt | 2 +-
.../resources/test_subscriptions_data.txt | 0
.../src/linuxMain/cinterop/libs.def | 0
.../ballast}/crypto/CryptoProvider.linux.kt | 2 +-
.../kotlin/ballast}/net/HttpClient.linux.kt | 2 +-
settings.gradle.kts | 4 ++--
35 files changed, 53 insertions(+), 53 deletions(-)
rename {kostr-core => ballast-core}/.gitignore (100%)
rename {kostr-core => ballast-core}/build.gradle.kts (99%)
rename {kostr-core/src/androidInstrumentedTest/kotlin/ktnostr => ballast-core/src/androidInstrumentedTest/kotlin/ballast}/android/ExampleInstrumentedTest.kt (96%)
rename {kostr-core => ballast-core}/src/androidMain/AndroidManifest.xml (100%)
rename {kostr-core/src/androidUnitTest/kotlin/ktnostr => ballast-core/src/androidUnitTest/kotlin/ballast}/android/ExampleUnitTest.kt (94%)
rename {kostr-core/src/appleMain/kotlin/ktnostr => ballast-core/src/appleMain/kotlin/ballast}/crypto/CryptoProvider.apple.kt (93%)
rename {kostr-core/src/appleMain/kotlin/ktnostr => ballast-core/src/appleMain/kotlin/ballast}/net/HttpClient.apple.kt (91%)
rename {kostr-core/src/commonJvmMain/kotlin/ktnostr => ballast-core/src/commonJvmMain/kotlin/ballast}/crypto/CryptoProvider.commonJvm.kt (95%)
rename {kostr-core/src/commonJvmMain/kotlin/ktnostr => ballast-core/src/commonJvmMain/kotlin/ballast}/net/HttpClient.commonJvm.kt (89%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/DateTimeUtils.kt (98%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/crypto/CryptoProvider.kt (90%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/crypto/CryptoUtils.kt (99%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/net/HttpClient.kt (84%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/net/NostrService.kt (97%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/Event.kt (97%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/EventExt.kt (98%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/Events.kt (96%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/NostrErrors.kt (97%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/NostrFilter.kt (99%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/Tag.kt (99%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/client/ClientMessage.kt (98%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/relay/Relay.kt (89%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/relay/RelayMessage.kt (99%)
rename {kostr-core/src/commonMain/kotlin/ktnostr => ballast-core/src/commonMain/kotlin/ballast}/nostr/relay/RelayPool.kt (95%)
rename {kostr-core/src/commonTest/kotlin/ktnostr => ballast-core/src/commonTest/kotlin/ballast}/crypto/CryptoUtilsTest.kt (98%)
rename {kostr-core/src/commonTest/kotlin/ktnostr => ballast-core/src/commonTest/kotlin/ballast}/nostr/EventTests.kt (99%)
rename {kostr-core/src/commonTest/kotlin/ktnostr => ballast-core/src/commonTest/kotlin/ballast}/nostr/NostrFilterTest.kt (98%)
rename {kostr-core/src/commonTest/kotlin/ktnostr => ballast-core/src/commonTest/kotlin/ballast}/nostr/NostrTests.kt (99%)
rename {kostr-core/src/commonTest/kotlin/ktnostr => ballast-core/src/commonTest/kotlin/ballast}/nostr/client/ClientMessageTests.kt (98%)
rename {kostr-core/src/commonTest/kotlin/ktnostr => ballast-core/src/commonTest/kotlin/ballast}/nostr/relay/RelayMessageTests.kt (98%)
rename {kostr-core => ballast-core}/src/commonTest/resources/test_subscriptions_data.txt (100%)
rename {kostr-core => ballast-core}/src/linuxMain/cinterop/libs.def (100%)
rename {kostr-core/src/linuxMain/kotlin/ktnostr => ballast-core/src/linuxMain/kotlin/ballast}/crypto/CryptoProvider.linux.kt (93%)
rename {kostr-core/src/linuxMain/kotlin/ktnostr => ballast-core/src/linuxMain/kotlin/ballast}/net/HttpClient.linux.kt (90%)
diff --git a/kostr-core/.gitignore b/ballast-core/.gitignore
similarity index 100%
rename from kostr-core/.gitignore
rename to ballast-core/.gitignore
diff --git a/kostr-core/build.gradle.kts b/ballast-core/build.gradle.kts
similarity index 99%
rename from kostr-core/build.gradle.kts
rename to ballast-core/build.gradle.kts
index 94d1f87..3b3067c 100644
--- a/kostr-core/build.gradle.kts
+++ b/ballast-core/build.gradle.kts
@@ -201,7 +201,7 @@ kotlin {
}
android {
- namespace = "ktnostr.android"
+ namespace = "ballast.android"
compileSdk = 34
defaultConfig {
minSdk = 21
diff --git a/kostr-core/src/androidInstrumentedTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt b/ballast-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt
similarity index 96%
rename from kostr-core/src/androidInstrumentedTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt
rename to ballast-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt
index 0d4e001..de71c84 100644
--- a/kostr-core/src/androidInstrumentedTest/kotlin/ktnostr/android/ExampleInstrumentedTest.kt
+++ b/ballast-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt
@@ -1,4 +1,4 @@
-package ktnostr.android
+package ballast.android
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
diff --git a/kostr-core/src/androidMain/AndroidManifest.xml b/ballast-core/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from kostr-core/src/androidMain/AndroidManifest.xml
rename to ballast-core/src/androidMain/AndroidManifest.xml
diff --git a/kostr-core/src/androidUnitTest/kotlin/ktnostr/android/ExampleUnitTest.kt b/ballast-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt
similarity index 94%
rename from kostr-core/src/androidUnitTest/kotlin/ktnostr/android/ExampleUnitTest.kt
rename to ballast-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt
index a1181db..399bada 100644
--- a/kostr-core/src/androidUnitTest/kotlin/ktnostr/android/ExampleUnitTest.kt
+++ b/ballast-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt
@@ -1,4 +1,4 @@
-package ktnostr.android
+package ballast.android
import org.junit.Assert.assertEquals
import org.junit.Test
diff --git a/kostr-core/src/appleMain/kotlin/ktnostr/crypto/CryptoProvider.apple.kt b/ballast-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt
similarity index 93%
rename from kostr-core/src/appleMain/kotlin/ktnostr/crypto/CryptoProvider.apple.kt
rename to ballast-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt
index 714c8d2..05ff28b 100644
--- a/kostr-core/src/appleMain/kotlin/ktnostr/crypto/CryptoProvider.apple.kt
+++ b/ballast-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt
@@ -1,4 +1,4 @@
-package ktnostr.crypto
+package ballast.crypto
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.providers.apple.Apple
diff --git a/kostr-core/src/appleMain/kotlin/ktnostr/net/HttpClient.apple.kt b/ballast-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt
similarity index 91%
rename from kostr-core/src/appleMain/kotlin/ktnostr/net/HttpClient.apple.kt
rename to ballast-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt
index 58b9810..03ae645 100644
--- a/kostr-core/src/appleMain/kotlin/ktnostr/net/HttpClient.apple.kt
+++ b/ballast-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt
@@ -1,4 +1,4 @@
-package ktnostr.net
+package ballast.net
import io.ktor.client.*
import io.ktor.client.engine.darwin.*
diff --git a/kostr-core/src/commonJvmMain/kotlin/ktnostr/crypto/CryptoProvider.commonJvm.kt b/ballast-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt
similarity index 95%
rename from kostr-core/src/commonJvmMain/kotlin/ktnostr/crypto/CryptoProvider.commonJvm.kt
rename to ballast-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt
index 29c8f52..07b32d9 100644
--- a/kostr-core/src/commonJvmMain/kotlin/ktnostr/crypto/CryptoProvider.commonJvm.kt
+++ b/ballast-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt
@@ -1,4 +1,4 @@
-package ktnostr.crypto
+package ballast.crypto
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.providers.jdk.JDK
diff --git a/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt b/ballast-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt
similarity index 89%
rename from kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt
rename to ballast-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt
index a8d5fc2..243e415 100644
--- a/kostr-core/src/commonJvmMain/kotlin/ktnostr/net/HttpClient.commonJvm.kt
+++ b/ballast-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt
@@ -1,4 +1,4 @@
-package ktnostr.net
+package ballast.net
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/DateTimeUtils.kt b/ballast-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt
similarity index 98%
rename from kostr-core/src/commonMain/kotlin/ktnostr/DateTimeUtils.kt
rename to ballast-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt
index 952637a..3b17d47 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/DateTimeUtils.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt
@@ -1,4 +1,4 @@
-package ktnostr
+package ballast
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/crypto/CryptoProvider.kt b/ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt
similarity index 90%
rename from kostr-core/src/commonMain/kotlin/ktnostr/crypto/CryptoProvider.kt
rename to ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt
index 5befc8a..f7562c1 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/crypto/CryptoProvider.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt
@@ -1,4 +1,4 @@
-package ktnostr.crypto
+package ballast.crypto
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.random.CryptographyRandom
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/crypto/CryptoUtils.kt b/ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt
similarity index 99%
rename from kostr-core/src/commonMain/kotlin/ktnostr/crypto/CryptoUtils.kt
rename to ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt
index 7e16e04..133a709 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/crypto/CryptoUtils.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt
@@ -1,6 +1,6 @@
//@file:JvmName("CryptoUtils")
-package ktnostr.crypto
+package ballast.crypto
import dev.whyoleg.cryptography.algorithms.SHA256
import fr.acinq.secp256k1.Hex
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/net/HttpClient.kt b/ballast-core/src/commonMain/kotlin/ballast/net/HttpClient.kt
similarity index 84%
rename from kostr-core/src/commonMain/kotlin/ktnostr/net/HttpClient.kt
rename to ballast-core/src/commonMain/kotlin/ballast/net/HttpClient.kt
index 758fb64..19324c7 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/net/HttpClient.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/net/HttpClient.kt
@@ -1,4 +1,4 @@
-package ktnostr.net
+package ballast.net
import io.ktor.client.*
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt b/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
similarity index 97%
rename from kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt
rename to ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
index 1f767ba..a607a8c 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/net/NostrService.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
@@ -1,4 +1,4 @@
-package ktnostr.net
+package ballast.net
import io.ktor.client.*
import io.ktor.client.plugins.logging.*
@@ -10,13 +10,13 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.encodeToString
-import ktnostr.formattedDateTime
-import ktnostr.nostr.Event
-import ktnostr.nostr.client.ClientMessage
-import ktnostr.nostr.client.RequestMessage
-import ktnostr.nostr.deserializedEvent
-import ktnostr.nostr.eventMapper
-import ktnostr.nostr.relay.*
+import ballast.formattedDateTime
+import ballast.nostr.Event
+import ballast.nostr.client.ClientMessage
+import ballast.nostr.client.RequestMessage
+import ballast.nostr.deserializedEvent
+import ballast.nostr.eventMapper
+import ballast.nostr.relay.*
import kotlin.coroutines.CoroutineContext
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Event.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/Event.kt
similarity index 97%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/Event.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/Event.kt
index 86929c8..0c41c00 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Event.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/Event.kt
@@ -1,13 +1,13 @@
-package ktnostr.nostr
+package ballast.nostr
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonArray
-import ktnostr.crypto.CryptoUtils
-import ktnostr.crypto.toHexString
+import ballast.crypto.CryptoUtils
+import ballast.crypto.toHexString
/**
* The Event class representing the Nostr Event.
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/EventExt.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
similarity index 98%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/EventExt.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
index 805ab25..4d74796 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/EventExt.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
@@ -1,4 +1,4 @@
-package ktnostr.nostr
+package ballast.nostr
import fr.acinq.secp256k1.Hex
import kotlinx.serialization.ExperimentalSerializationApi
@@ -10,7 +10,7 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
-import ktnostr.crypto.CryptoUtils
+import ballast.crypto.CryptoUtils
internal val eventMapper = Json
@OptIn(ExperimentalSerializationApi::class)
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Events.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt
similarity index 96%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/Events.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt
index ae15ab7..0c2b8cc 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Events.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt
@@ -1,11 +1,11 @@
@file:JvmName("EventUtils")
-package ktnostr.nostr
+package ballast.nostr
import fr.acinq.secp256k1.Secp256k1
-import ktnostr.crypto.CryptoUtils
-import ktnostr.crypto.toBytes
-import ktnostr.crypto.toHexString
-import ktnostr.currentSystemTimestamp
+import ballast.crypto.CryptoUtils
+import ballast.crypto.toBytes
+import ballast.crypto.toHexString
+import ballast.currentSystemTimestamp
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrErrors.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt
similarity index 97%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrErrors.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt
index 2f33718..e15cc21 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrErrors.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt
@@ -1,4 +1,4 @@
-package ktnostr.nostr
+package ballast.nostr
//The general class of Nostr Errors.
sealed class NostrException : RuntimeException {
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrFilter.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt
similarity index 99%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrFilter.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt
index c101971..ee58925 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/NostrFilter.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt
@@ -1,4 +1,4 @@
-package ktnostr.nostr
+package ballast.nostr
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Tag.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
similarity index 99%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/Tag.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
index 975d120..589e004 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/Tag.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
@@ -1,5 +1,5 @@
//@file:JvmName("Tag")
-package ktnostr.nostr
+package ballast.nostr
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/client/ClientMessage.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
similarity index 98%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/client/ClientMessage.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
index 81cbcf8..4b9f70e 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/client/ClientMessage.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
@@ -1,4 +1,4 @@
-package ktnostr.nostr.client
+package ballast.nostr.client
import com.benasher44.uuid.bytes
import com.benasher44.uuid.uuid4
@@ -12,8 +12,8 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*
-import ktnostr.nostr.Event
-import ktnostr.nostr.NostrFilter
+import ballast.nostr.Event
+import ballast.nostr.NostrFilter
@Serializable(with = ClientMessage.MessageSerializer::class)
sealed class ClientMessage(open val messageType: String){
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/Relay.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt
similarity index 89%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/Relay.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt
index 1531aeb..a83097c 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/Relay.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt
@@ -1,4 +1,4 @@
-package ktnostr.nostr.relay
+package ballast.nostr.relay
class Relay(
val relayURI: String,
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/RelayMessage.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt
similarity index 99%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/RelayMessage.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt
index 0fb7dc3..5aac261 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/RelayMessage.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt
@@ -1,6 +1,6 @@
-package ktnostr.nostr.relay
+package ballast.nostr.relay
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
@@ -177,7 +177,7 @@ sealed class RelayMessage(){
* Typically, the data is a JSON array of 3 elements, which look like this: [[EVENT, subscriptionId, eventJson]].
* Though the eventJson returned here is in a String format, it will need to be parsed for a client to make
* sense of it. You can do so using the provided deserializedEvent() function.
- * @see ktnostr.nostr.deserializedEvent
+ * @see ballast.nostr.deserializedEvent
*/
@Serializable
diff --git a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/RelayPool.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
similarity index 95%
rename from kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/RelayPool.kt
rename to ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
index 0f0792b..d0d7dff 100644
--- a/kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/RelayPool.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
@@ -1,6 +1,6 @@
-package ktnostr.nostr.relay
+package ballast.nostr.relay
-import ktnostr.nostr.RelayError
+import ballast.nostr.RelayError
import kotlin.jvm.JvmStatic
class RelayPool {
diff --git a/kostr-core/src/commonTest/kotlin/ktnostr/crypto/CryptoUtilsTest.kt b/ballast-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt
similarity index 98%
rename from kostr-core/src/commonTest/kotlin/ktnostr/crypto/CryptoUtilsTest.kt
rename to ballast-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt
index b29dd03..f78cacd 100644
--- a/kostr-core/src/commonTest/kotlin/ktnostr/crypto/CryptoUtilsTest.kt
+++ b/ballast-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt
@@ -1,4 +1,4 @@
-package ktnostr.crypto
+package ballast.crypto
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/EventTests.kt b/ballast-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt
similarity index 99%
rename from kostr-core/src/commonTest/kotlin/ktnostr/nostr/EventTests.kt
rename to ballast-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt
index e20e09d..a3544b3 100644
--- a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/EventTests.kt
+++ b/ballast-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt
@@ -1,4 +1,4 @@
-package ktnostr.nostr
+package ballast.nostr
import kotlinx.serialization.json.Json
import kotlin.test.Test
diff --git a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrFilterTest.kt b/ballast-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt
similarity index 98%
rename from kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrFilterTest.kt
rename to ballast-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt
index a5acb3b..fa790ca 100644
--- a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrFilterTest.kt
+++ b/ballast-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt
@@ -1,8 +1,8 @@
-package ktnostr.nostr
+package ballast.nostr
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
-import ktnostr.currentSystemTimestamp
+import ballast.currentSystemTimestamp
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrTests.kt b/ballast-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt
similarity index 99%
rename from kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrTests.kt
rename to ballast-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt
index 26594b8..ac8d1f9 100644
--- a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/NostrTests.kt
+++ b/ballast-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt
@@ -1,4 +1,4 @@
-package ktnostr.nostr
+package ballast.nostr
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/client/ClientMessageTests.kt b/ballast-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt
similarity index 98%
rename from kostr-core/src/commonTest/kotlin/ktnostr/nostr/client/ClientMessageTests.kt
rename to ballast-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt
index a920607..02a9983 100644
--- a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/client/ClientMessageTests.kt
+++ b/ballast-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt
@@ -1,9 +1,9 @@
-package ktnostr.nostr.client
+package ballast.nostr.client
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
-import ktnostr.nostr.EventKind
-import ktnostr.nostr.NostrFilter
+import ballast.nostr.EventKind
+import ballast.nostr.NostrFilter
import kotlin.jvm.JvmStatic
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/relay/RelayMessageTests.kt b/ballast-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt
similarity index 98%
rename from kostr-core/src/commonTest/kotlin/ktnostr/nostr/relay/RelayMessageTests.kt
rename to ballast-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt
index 336ddf2..4813ac3 100644
--- a/kostr-core/src/commonTest/kotlin/ktnostr/nostr/relay/RelayMessageTests.kt
+++ b/ballast-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt
@@ -1,4 +1,4 @@
-package ktnostr.nostr.relay
+package ballast.nostr.relay
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
diff --git a/kostr-core/src/commonTest/resources/test_subscriptions_data.txt b/ballast-core/src/commonTest/resources/test_subscriptions_data.txt
similarity index 100%
rename from kostr-core/src/commonTest/resources/test_subscriptions_data.txt
rename to ballast-core/src/commonTest/resources/test_subscriptions_data.txt
diff --git a/kostr-core/src/linuxMain/cinterop/libs.def b/ballast-core/src/linuxMain/cinterop/libs.def
similarity index 100%
rename from kostr-core/src/linuxMain/cinterop/libs.def
rename to ballast-core/src/linuxMain/cinterop/libs.def
diff --git a/kostr-core/src/linuxMain/kotlin/ktnostr/crypto/CryptoProvider.linux.kt b/ballast-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt
similarity index 93%
rename from kostr-core/src/linuxMain/kotlin/ktnostr/crypto/CryptoProvider.linux.kt
rename to ballast-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt
index 454ac1d..470c0f3 100644
--- a/kostr-core/src/linuxMain/kotlin/ktnostr/crypto/CryptoProvider.linux.kt
+++ b/ballast-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt
@@ -1,4 +1,4 @@
-package ktnostr.crypto
+package ballast.crypto
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.providers.openssl3.Openssl3
diff --git a/kostr-core/src/linuxMain/kotlin/ktnostr/net/HttpClient.linux.kt b/ballast-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt
similarity index 90%
rename from kostr-core/src/linuxMain/kotlin/ktnostr/net/HttpClient.linux.kt
rename to ballast-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt
index 9d36976..f53bb21 100644
--- a/kostr-core/src/linuxMain/kotlin/ktnostr/net/HttpClient.linux.kt
+++ b/ballast-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt
@@ -1,4 +1,4 @@
-package ktnostr.net
+package ballast.net
import io.ktor.client.*
import io.ktor.client.engine.cio.*
diff --git a/settings.gradle.kts b/settings.gradle.kts
index b9f6823..9132f08 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -13,6 +13,6 @@ dependencyResolutionManagement {
}
}
-rootProject.name = "kostr"
-include("kostr-core")
+rootProject.name = "ballast"
+include("ballast-core")
//include(":kostr-android")
From 93acacf0e0a13e0f798bf745ca7525d2d5361630 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 15:30:11 +0100
Subject: [PATCH 14/35] Move to vanniktech publish plugin. Add a publish
release workflow.
---
.github/workflows/publish.yml | 25 ++++++++++++++
ballast-core/build.gradle.kts | 2 +-
build.gradle.kts | 62 ++++++++++++++++++++++++++++++-----
3 files changed, 79 insertions(+), 10 deletions(-)
create mode 100644 .github/workflows/publish.yml
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..4c7d2c2
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,25 @@
+
+name: Publish
+on:
+ release:
+ types: [released, prereleased]
+jobs:
+ publish:
+ name: Release build and publish
+ runs-on: macOS-latest
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v4
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin'
+ java-version: 17
+ - name: Publish to MavenCentral
+ run: ./gradlew publishToMavenCentral --no-configuration-cache
+ env:
+ ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
+ ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
+ ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }}
+ ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }}
+ ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY_CONTENTS }}
\ No newline at end of file
diff --git a/ballast-core/build.gradle.kts b/ballast-core/build.gradle.kts
index 3b3067c..ef2e2f8 100644
--- a/ballast-core/build.gradle.kts
+++ b/ballast-core/build.gradle.kts
@@ -201,7 +201,7 @@ kotlin {
}
android {
- namespace = "ballast.android"
+ namespace = "io.github.kotlingeekdev.ballast.android"
compileSdk = 34
defaultConfig {
minSdk = 21
diff --git a/build.gradle.kts b/build.gradle.kts
index 0b30cc8..95c6253 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,3 +1,5 @@
+import com.vanniktech.maven.publish.SonatypeHost
+
buildscript {
val kotlinVersion = "2.0.20"
@@ -14,6 +16,7 @@ plugins {
kotlin("multiplatform") version "2.0.20" apply false
id("com.android.library") version "8.2.2" apply false
id("org.jetbrains.kotlinx.atomicfu") version "0.25.0"
+ id("com.vanniktech.maven.publish") version "0.30.0"
//id("org.jetbrains.kotlin.android") version "2.0.0" apply false
//id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" apply false
@@ -22,22 +25,63 @@ plugins {
allprojects {
apply(plugin = "org.jetbrains.kotlin.plugin.serialization")
- apply(plugin = "maven-publish")
+ apply(plugin = "com.vanniktech.maven.publish")
+// apply(plugin = "maven-publish")
+
+
- group = "com.github.KotlinGeekDev"
+ group = "io.github.kotlingeekdev"
version = "1.0-beta-06"
- val javadocJar = tasks.register("javadocJar") {
- archiveClassifier.set("javadoc")
- }
+// val javadocJar = tasks.register("javadocJar") {
+// archiveClassifier.set("javadoc")
+// }
+
+ mavenPublishing {
+ publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
+ signAllPublications()
- extensions.configure {
- publications.withType().configureEach {
- version = project.version.toString()
- artifact(javadocJar)
+ coordinates(group.toString(), "ballast", version.toString())
+// configure(KotlinMultiplatform(
+// javadocJar = JavadocJar.Javadoc(),
+// sourcesJar = true
+// ))
+
+ pom {
+ name = "Ballast"
+ description = " A Kotlin Multiplatform library for Nostr"
+ url = "https://github.com/KotlinGeekDev/Ballast"
+
+ licenses {
+ license {
+ name = "The MIT License"
+ url = "https://opensource.org/license/MIT"
+ distribution = "https://opensource.org/license/MIT"
+ }
+ }
+
+ developers {
+ developer {
+ name = "KotlinGeekDev"
+ email = "kotlingeek@protonmail.com"
+ url = "https://github.com/KotlinGeekDev"
+ }
+ }
+
+ scm {
+ connection = "scm:git:git://github.com/KotlinGeekDev/Ballast.git"
+ url = "https://github.com/KotlinGeekDev/Ballast"
+ }
}
}
+// extensions.configure {
+// publications.withType().configureEach {
+// version = project.version.toString()
+// artifact(javadocJar)
+// }
+// }
+
}
From a6e2131dd73642c1435b935c064ba3f6ef7e65b4 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 15:48:05 +0100
Subject: [PATCH 15/35] Enable Jitpack support and automate release
publication.
---
.github/workflows/publish.yml | 2 +-
build.gradle.kts | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 4c7d2c2..f69f6e3 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -16,7 +16,7 @@ jobs:
distribution: 'temurin'
java-version: 17
- name: Publish to MavenCentral
- run: ./gradlew publishToMavenCentral --no-configuration-cache
+ run: ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
diff --git a/build.gradle.kts b/build.gradle.kts
index 95c6253..a372eb6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -28,7 +28,7 @@ allprojects {
apply(plugin = "com.vanniktech.maven.publish")
// apply(plugin = "maven-publish")
-
+ val isJitpack = System.getenv("JITPACK") == "true"
group = "io.github.kotlingeekdev"
version = "1.0-beta-06"
@@ -39,7 +39,9 @@ allprojects {
mavenPublishing {
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
- signAllPublications()
+ if (!isJitpack){
+ signAllPublications()
+ }
coordinates(group.toString(), "ballast", version.toString())
// configure(KotlinMultiplatform(
From 3855c30db8d0c265eb00aa01af77850d3865a094 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 16:06:28 +0100
Subject: [PATCH 16/35] Rename Tag properties to align with meaning in protocol
specs.
---
.../commonMain/kotlin/ballast/nostr/Events.kt | 4 ++--
.../commonMain/kotlin/ballast/nostr/Tag.kt | 20 +++++++++----------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt
index 0c2b8cc..cc56595 100644
--- a/ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt
@@ -30,8 +30,8 @@ object Events {
val normalizedTags = tags.map {
Tag(it.identifier,
it.description,
- it.recommendedRelayUrl,
- it.petname)
+ it.content,
+ it.customContent)
}
return Event(eventID, publicKeyHex, timeStamp, eventKind, normalizedTags, content, signatureString)
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
index 589e004..50e9f72 100644
--- a/ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
@@ -16,17 +16,17 @@ import kotlinx.serialization.encoding.Encoder
* of relays you already have, and a petname or username(optional),
* when a tag contains an identity's alias(or username).
*
- * @param identifier The tag identifier, as a string
- * @param description The tag's contents, as a string
- * @param recommendedRelayUrl (optional) A recommended relay url, as a string
+ * @param identifier The tag key, as a string
+ * @param description The tag value, as a string
+ * @param content (optional) A custom field with no particular meaning(generally used for relay recommendation), as a string
*/
@Serializable(with = Tag.TagSerializer::class)
data class Tag(
val identifier: String, val description: String,
- val recommendedRelayUrl: String? = null,
- val petname: String? = null
+ val content: String? = null,
+ val customContent: String? = null
) {
@OptIn(ExperimentalSerializationApi::class)
@@ -38,8 +38,8 @@ data class Tag(
buildList {
add(identifier)
add(description)
- if (recommendedRelayUrl != null) add(recommendedRelayUrl)
- if (petname != null) add(petname)
+ if (content != null) add(content)
+ if (customContent != null) add(customContent)
}.toTypedArray()
}
encoder.encodeSerializableValue(builtinSerializer, arrayOfValues)
@@ -70,10 +70,10 @@ data class Tag(
//fun List.toStringList(): List> {
// val tagStringList: MutableList> = mutableListOf()
// this.forEach { tag ->
-// val elementList: List = if (tag.recommendedRelayUrl != null){
-// listOf(tag.identifier, tag.description, tag.recommendedRelayUrl)
+// val elementList: List = if (tag.customContent != null){
+// listOf(tag.identifier, tag.content, tag.customContent)
// } else {
-// listOf(tag.identifier, tag.description)
+// listOf(tag.identifier, tag.content)
// }
// tagStringList.add(elementList)
// }
From 008137c228fc52103f12dff6e980500faa56ca9a Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 16:14:17 +0100
Subject: [PATCH 17/35] New release: v.10-beta-07
---
build.gradle.kts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index a372eb6..e053c0b 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -31,7 +31,7 @@ allprojects {
val isJitpack = System.getenv("JITPACK") == "true"
group = "io.github.kotlingeekdev"
- version = "1.0-beta-06"
+ version = "1.0-beta-07"
// val javadocJar = tasks.register("javadocJar") {
// archiveClassifier.set("javadoc")
From f4fdb296a3411212f39310c9827db57efe0a193f Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 17:00:06 +0100
Subject: [PATCH 18/35] Update publish workflow.
---
.github/workflows/publish.yml | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index f69f6e3..9523ddb 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,8 +1,14 @@
name: Publish
on:
+ push:
+ branches: ["develop"]
release:
- types: [released, prereleased]
+ types: [released]
+
+concurrency:
+ cancel-in-progress: true
+
jobs:
publish:
name: Release build and publish
@@ -10,13 +16,13 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v4
- - name: Set up JDK 21
+ - name: Set up JDK 17
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: 17
- name: Publish to MavenCentral
- run: ./gradlew publishAndReleaseToMavenCentral --no-configuration-cache
+ run: ./gradlew publishToMavenCentral --no-configuration-cache
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
From f39145ddde429a2bbcae5857d4928963e99e3ee0 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 17:02:32 +0100
Subject: [PATCH 19/35] Update publish workflow(again).
---
.github/workflows/publish.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 9523ddb..dd86c9f 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -6,8 +6,8 @@ on:
release:
types: [released]
-concurrency:
- cancel-in-progress: true
+#concurrency:
+# cancel-in-progress: true
jobs:
publish:
From 103efac416018b50c8fbbbae92eda3dedc08de08 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 17:31:09 +0100
Subject: [PATCH 20/35] Update README and disable build on push.
---
.github/workflows/publish.yml | 4 ++--
README.md | 13 +++++++++++--
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index dd86c9f..8e3b4a3 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,8 +1,8 @@
name: Publish
on:
- push:
- branches: ["develop"]
+# push:
+# branches: ["develop"]
release:
types: [released]
diff --git a/README.md b/README.md
index e34c631..3582fff 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,15 @@ Note: This is still in development and very incomplete.
* The Nostr protocol specs can be found [here](https://github.com/nostr-protocol/nips).
## How to include the libary
+You can include the library from either Maven Central or Jitpack.
+
+### Maven
+You can include the library in the common source set like this:
+```kotlin
+dependencies {
+ implementation("io.github.kotlingeekdev:ballast:1.0-beta-07")
+}
+```
Inside your root-level `build.gradle(.kts)` file, you should add `jitpack`:
``` kotlin
// build.gradle.kts
@@ -61,7 +70,7 @@ then, in your module's `build.gradle(.kts)`, you need to add:
// build.gradle.kts
dependencies {
//...
- implementation("com.github.KotlinGeekDev.kostr:kostr-core:v1.0-beta-06")
+ implementation("com.github.KotlinGeekDev.Ballast:ballast:1.0-beta-07")
}
@@ -71,7 +80,7 @@ If you're including it in an Android app, you can just add:
// app/build.gradle.kts
dependencies {
//...
- implementation("com.github.KotlinGeekDev.kostr:kostr-core-android:v1.0-beta-06")
+ implementation("com.github.KotlinGeekDev.Ballast:ballast-android:1.0-beta-07")
}
```
From ad7d4c5e59ed706f5bdebb45428eeb6d2dc20def Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 17:35:36 +0100
Subject: [PATCH 21/35] Add shields badge for maven central.
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 3582fff..8f89f63 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# Kostr
[](https://kotlinlang.org)
+[](https://search.maven.org/search?q=g:io.github.kotlingeekdev)


From a8794407e9aaefab6a7f9d575a2037f4e3aa8e06 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Wed, 12 Feb 2025 17:37:22 +0100
Subject: [PATCH 22/35] Clarify jitpack section in README.
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 8f89f63..d89041d 100644
--- a/README.md
+++ b/README.md
@@ -28,6 +28,8 @@ dependencies {
implementation("io.github.kotlingeekdev:ballast:1.0-beta-07")
}
```
+
+### Jitpack
Inside your root-level `build.gradle(.kts)` file, you should add `jitpack`:
``` kotlin
// build.gradle.kts
From 901e06a8c6647ae31f1ff61db33a2a8519b7e185 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Thu, 13 Feb 2025 22:02:37 +0100
Subject: [PATCH 23/35] Make slight adjustments to the customClient parameter.
---
.../kotlin/ballast/net/NostrService.kt | 28 ++++++-------------
1 file changed, 8 insertions(+), 20 deletions(-)
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt b/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
index a607a8c..9a914bf 100644
--- a/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
@@ -1,7 +1,13 @@
package ballast.net
+import ballast.formattedDateTime
+import ballast.nostr.Event
+import ballast.nostr.client.ClientMessage
+import ballast.nostr.client.RequestMessage
+import ballast.nostr.deserializedEvent
+import ballast.nostr.eventMapper
+import ballast.nostr.relay.*
import io.ktor.client.*
-import io.ktor.client.plugins.logging.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*
import kotlinx.atomicfu.atomic
@@ -10,19 +16,12 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.encodeToString
-import ballast.formattedDateTime
-import ballast.nostr.Event
-import ballast.nostr.client.ClientMessage
-import ballast.nostr.client.RequestMessage
-import ballast.nostr.deserializedEvent
-import ballast.nostr.eventMapper
-import ballast.nostr.relay.*
import kotlin.coroutines.CoroutineContext
class NostrService(
private val relayPool: RelayPool = RelayPool(),
- val customClient: HttpClient? = null
+ private val client: HttpClient = httpClient { install(WebSockets){} }
): CoroutineScope {
private val serviceDispatcher = Dispatchers.IO.limitedParallelism(
relayPool.getRelays().size,
@@ -30,17 +29,6 @@ class NostrService(
)
private val serviceMutex = Mutex()
- private val client = customClient
- ?: httpClient {
- install(WebSockets){
-
- }
-
- install(Logging){
-
- }
- }
-
override val coroutineContext: CoroutineContext
get() = serviceDispatcher
From 8b87d3647c8c36314bf2a83dbbc5ffcd11b52861 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Thu, 13 Feb 2025 22:08:18 +0100
Subject: [PATCH 24/35] NIP-05 support, using the
NostrUtils.getProfileInfoFromAddress() API, and with custom client support.
Add url/domain verification.
---
.../kotlin/ballast/net/NostrUtils.kt | 67 ++++
.../commonMain/kotlin/ballast/net/UrlUtil.kt | 291 ++++++++++++++++++
.../kotlin/ballast/nostr/NostrErrors.kt | 5 +
3 files changed, 363 insertions(+)
create mode 100644 ballast-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt
create mode 100644 ballast-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt b/ballast-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt
new file mode 100644
index 0000000..2a394c4
--- /dev/null
+++ b/ballast-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt
@@ -0,0 +1,67 @@
+package ballast.net
+
+import ballast.nostr.Nip05ValidationError
+import ballast.nostr.arraySerializer
+import ballast.nostr.eventMapper
+import io.ktor.client.*
+import io.ktor.client.plugins.*
+import io.ktor.client.request.*
+import io.ktor.client.statement.*
+import kotlinx.serialization.json.jsonArray
+import kotlinx.serialization.json.jsonObject
+import kotlinx.serialization.json.jsonPrimitive
+
+object NostrUtils {
+
+ suspend fun getProfileInfoFromAddress(
+ nip05: String,
+ client: HttpClient = httpClient()
+ ): Array {
+ val nameWithDomain = nip05.split("@")
+ if (nameWithDomain.size > 2 || nameWithDomain.isEmpty()) {
+ throw Nip05ValidationError("Likely a malformed address.")
+ }
+ else if (nameWithDomain.size == 1 || nameWithDomain[0].contentEquals("_")) {
+ val domain = nameWithDomain[0]
+ if (!UrlUtil.isValidUrl(domain)) throw Nip05ValidationError("Invalid identifier.")
+ val urlToUse = "https://${domain}/.well-known/nostr.json?name=_"
+ return fetchDetails(urlToUse, "_", client)
+
+ }
+ else {
+ val finalUrl = "https://${nameWithDomain[1]}/.well-known/nostr.json?name=${nameWithDomain[0]}"
+ return fetchDetails(finalUrl, nameWithDomain[0], client)
+ }
+ }
+
+ private suspend fun fetchDetails(composedUrl: String, userName: String, client: HttpClient): Array {
+ val obtainedResponse = client.config { followRedirects = false }.get(urlString = composedUrl)
+
+ if (obtainedResponse.status.value in 200..299){
+ val responseData = obtainedResponse.bodyAsText()
+
+ return parseResponseData(responseData, userName)
+ }
+ else throw ResponseException(obtainedResponse, obtainedResponse.status.description)
+ }
+
+ private fun parseResponseData(responseData: String, userName: String): Array {
+ val motherObject = eventMapper.parseToJsonElement(responseData).jsonObject
+ val namesChild = motherObject["names"]?.jsonObject
+ val profile = namesChild?.get(userName)?.jsonPrimitive?.content
+ if (profile == null) {
+ throw Nip05ValidationError("Could not find a corresponding pubkey for this address.")
+ }
+ else {
+ val relaysChild = motherObject["relays"]?.jsonObject
+ val userRelays = relaysChild?.get(profile)?.jsonArray
+ if (userRelays == null) {
+ return arrayOf(profile)
+ }
+ else {
+ val relayList = eventMapper.decodeFromJsonElement(arraySerializer, userRelays)
+ return arrayOf(profile, *relayList)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt b/ballast-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt
new file mode 100644
index 0000000..226f3d4
--- /dev/null
+++ b/ballast-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt
@@ -0,0 +1,291 @@
+/**
+ * The source code below originates from https://github.com/chRyNaN/validator.
+ * Credits : chRyNaN, Android URLUtil class devs.
+ */
+package ballast.net
+
+object UrlUtil {
+ private val URL_REGEX = Regex(WebRegexConstants.WEB_URL)
+ private val AUTO_URL_REGEX = Regex(WebRegexConstants.AUTOLINK_WEB_URL)
+
+ fun isValidUrl(url: String): Boolean {
+ if (!url.matches(URL_REGEX) && !url.matches(AUTO_URL_REGEX)) return false
+ return url.matches(URL_REGEX) || url.matches(AUTO_URL_REGEX)
+ }
+}
+
+object WebRegexConstants {
+
+ const val IP_ADDRESS = ("((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
+ + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
+ + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+ + "|[1-9][0-9]|[0-9]))")
+
+ /**
+ * Regex for an IPv6 Address.
+ *
+ * Note that this value is adapted from the following StackOverflow answer:
+ * https://stackoverflow.com/a/17871737/1478764
+ */
+ const val IPV6_ADDRESS =
+ ("(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}"
+ + "|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|"
+ + "([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|"
+ + "[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4})"
+ + "{0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.)"
+ + "{3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}"
+ + "[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))")
+
+ /**
+ * Regular expression to match all IANA top-level domains.
+ *
+ * List accurate as of 2015/11/24.
+ *
+ * List taken from: http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ */
+ private const val IANA_TOP_LEVEL_DOMAINS = ("(?:"
+ + "(?:aaa|aarp|abb|abbott|abogado|academy|accenture|accountant|accountants|aco|active"
+ + "|actor|ads|adult|aeg|aero|afl|agency|aig|airforce|airtel|allfinanz|alsace|amica|amsterdam"
+ + "|android|apartments|app|apple|aquarelle|aramco|archi|army|arpa|arte|asia|associates"
+ + "|attorney|auction|audio|auto|autos|axa|azure|a[cdefgilmoqrstuwxz])"
+ + "|(?:band|bank|bar|barcelona|barclaycard|barclays|bargains|bauhaus|bayern|bbc|bbva"
+ + "|bcn|beats|beer|bentley|berlin|best|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black"
+ + "|blackfriday|bloomberg|blue|bms|bmw|bnl|bnpparibas|boats|bom|bond|boo|boots|boutique"
+ + "|bradesco|bridgestone|broadway|broker|brother|brussels|budapest|build|builders|business"
+ + "|buzz|bzh|b[abdefghijmnorstvwyz])"
+ + "|(?:cab|cafe|cal|camera|camp|cancerresearch|canon|capetown|capital|car|caravan|cards"
+ + "|care|career|careers|cars|cartier|casa|cash|casino|cat|catering|cba|cbn|ceb|center|ceo"
+ + "|cern|cfa|cfd|chanel|channel|chat|cheap|chloe|christmas|chrome|church|cipriani|cisco"
+ + "|citic|city|cityeats|claims|cleaning|click|clinic|clothing|cloud|club|clubmed|coach"
+ + "|codes|coffee|college|cologne|com|commbank|community|company|computer|comsec|condos"
+ + "|construction|consulting|contractors|cooking|cool|coop|corsica|country|coupons|courses"
+ + "|credit|creditcard|creditunion|cricket|crown|crs|cruises|csc|cuisinella|cymru|cyou|c[acdfghiklmnoruvwxyz])"
+ + "|(?:dabur|dad|dance|date|dating|datsun|day|dclk|deals|degree|delivery|dell|delta"
+ + "|democrat|dental|dentist|desi|design|dev|diamonds|diet|digital|direct|directory|discount"
+ + "|dnp|docs|dog|doha|domains|doosan|download|drive|durban|dvag|d[ejkmoz])"
+ + "|(?:earth|eat|edu|education|email|emerck|energy|engineer|engineering|enterprises"
+ + "|epson|equipment|erni|esq|estate|eurovision|eus|events|everbank|exchange|expert|exposed"
+ + "|express|e[cegrstu])"
+ + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|fashion|feedback|ferrero|film"
+ + "|final|finance|financial|firmdale|fish|fishing|fit|fitness|flights|florist|flowers|flsmidth"
+ + "|fly|foo|football|forex|forsale|forum|foundation|frl|frogans|fund|furniture|futbol|fyi"
+ + "|f[ijkmor])"
+ + "|(?:gal|gallery|game|garden|gbiz|gdn|gea|gent|genting|ggee|gift|gifts|gives|giving"
+ + "|glass|gle|global|globo|gmail|gmo|gmx|gold|goldpoint|golf|goo|goog|google|gop|gov|grainger"
+ + "|graphics|gratis|green|gripe|group|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])"
+ + "|(?:hamburg|hangout|haus|healthcare|help|here|hermes|hiphop|hitachi|hiv|hockey|holdings"
+ + "|holiday|homedepot|homes|honda|horse|host|hosting|hoteles|hotmail|house|how|hsbc|hyundai"
+ + "|h[kmnrtu])"
+ + "|(?:ibm|icbc|ice|icu|ifm|iinet|immo|immobilien|industries|infiniti|info|ing|ink|institute"
+ + "|insure|int|international|investments|ipiranga|irish|ist|istanbul|itau|iwc|i[delmnoqrst])"
+ + "|(?:jaguar|java|jcb|jetzt|jewelry|jlc|jll|jobs|joburg|jprs|juegos|j[emop])"
+ + "|(?:kaufen|kddi|kia|kim|kinder|kitchen|kiwi|koeln|komatsu|krd|kred|kyoto|k[eghimnprwyz])"
+ + "|(?:lacaixa|lancaster|land|landrover|lasalle|lat|latrobe|law|lawyer|lds|lease|leclerc"
+ + "|legal|lexus|lgbt|liaison|lidl|life|lifestyle|lighting|limited|limo|linde|link|live"
+ + "|lixil|loan|loans|lol|london|lotte|lotto|love|ltd|ltda|lupin|luxe|luxury|l[abcikrstuvy])"
+ + "|(?:madrid|maif|maison|man|management|mango|market|marketing|markets|marriott|mba"
+ + "|media|meet|melbourne|meme|memorial|men|menu|meo|miami|microsoft|mil|mini|mma|mobi|moda"
+ + "|moe|moi|mom|monash|money|montblanc|mormon|mortgage|moscow|motorcycles|mov|movie|movistar"
+ + "|mtn|mtpc|mtr|museum|mutuelle|m[acdeghklmnopqrstuvwxyz])"
+ + "|(?:nadex|nagoya|name|navy|nec|net|netbank|network|neustar|new|news|nexus|ngo|nhk"
+ + "|nico|ninja|nissan|nokia|nra|nrw|ntt|nyc|n[acefgilopruz])"
+ + "|(?:obi|office|okinawa|omega|one|ong|onl|online|ooo|oracle|orange|org|organic|osaka"
+ + "|otsuka|ovh|om)"
+ + "|(?:page|panerai|paris|partners|parts|party|pet|pharmacy|philips|photo|photography"
+ + "|photos|physio|piaget|pics|pictet|pictures|ping|pink|pizza|place|play|playstation|plumbing"
+ + "|plus|pohl|poker|porn|post|praxi|press|pro|prod|productions|prof|properties|property"
+ + "|protection|pub|p[aefghklmnrstwy])"
+ + "|(?:qpon|quebec|qa)"
+ + "|(?:racing|realtor|realty|recipes|red|redstone|rehab|reise|reisen|reit|ren|rent|rentals"
+ + "|repair|report|republican|rest|restaurant|review|reviews|rich|ricoh|rio|rip|rocher|rocks"
+ + "|rodeo|rsvp|ruhr|run|rwe|ryukyu|r[eosuw])"
+ + "|(?:saarland|sakura|sale|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|saxo"
+ + "|sbs|sca|scb|schmidt|scholarships|school|schule|schwarz|science|scor|scot|seat|security"
+ + "|seek|sener|services|seven|sew|sex|sexy|shiksha|shoes|show|shriram|singles|site|ski"
+ + "|sky|skype|sncf|soccer|social|software|sohu|solar|solutions|sony|soy|space|spiegel|spreadbetting"
+ + "|srl|stada|starhub|statoil|stc|stcgroup|stockholm|studio|study|style|sucks|supplies"
+ + "|supply|support|surf|surgery|suzuki|swatch|swiss|sydney|systems|s[abcdeghijklmnortuvxyz])"
+ + "|(?:tab|taipei|tatamotors|tatar|tattoo|tax|taxi|team|tech|technology|tel|telefonica"
+ + "|temasek|tennis|thd|theater|theatre|tickets|tienda|tips|tires|tirol|today|tokyo|tools"
+ + "|top|toray|toshiba|tours|town|toyota|toys|trade|trading|training|travel|trust|tui|t[cdfghjklmnortvwz])"
+ + "|(?:ubs|university|uno|uol|u[agksyz])"
+ + "|(?:vacations|vana|vegas|ventures|versicherung|vet|viajes|video|villas|vin|virgin"
+ + "|vision|vista|vistaprint|viva|vlaanderen|vodka|vote|voting|voto|voyage|v[aceginu])"
+ + "|(?:wales|walter|wang|watch|webcam|website|wed|wedding|weir|whoswho|wien|wiki|williamhill"
+ + "|win|windows|wine|wme|work|works|world|wtc|wtf|w[fs])"
+ + "|(?:\u03b5\u03bb|\u0431\u0435\u043b|\u0434\u0435\u0442\u0438|\u043a\u043e\u043c|\u043c\u043a\u0434"
+ + "|\u043c\u043e\u043d|\u043c\u043e\u0441\u043a\u0432\u0430|\u043e\u043d\u043b\u0430\u0439\u043d"
+ + "|\u043e\u0440\u0433|\u0440\u0443\u0441|\u0440\u0444|\u0441\u0430\u0439\u0442|\u0441\u0440\u0431"
+ + "|\u0443\u043a\u0440|\u049b\u0430\u0437|\u0570\u0561\u0575|\u05e7\u05d5\u05dd|\u0627\u0631\u0627\u0645\u0643\u0648"
+ + "|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629"
+ + "|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0627\u06cc\u0631\u0627\u0646"
+ + "|\u0628\u0627\u0632\u0627\u0631|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633"
+ + "|\u0633\u0648\u062f\u0627\u0646|\u0633\u0648\u0631\u064a\u0629|\u0634\u0628\u0643\u0629"
+ + "|\u0639\u0631\u0627\u0642|\u0639\u0645\u0627\u0646|\u0641\u0644\u0633\u0637\u064a\u0646"
+ + "|\u0642\u0637\u0631|\u0643\u0648\u0645|\u0645\u0635\u0631|\u0645\u0644\u064a\u0633\u064a\u0627"
+ + "|\u0645\u0648\u0642\u0639|\u0915\u0949\u092e|\u0928\u0947\u091f|\u092d\u093e\u0930\u0924"
+ + "|\u0938\u0902\u0917\u0920\u0928|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4"
+ + "|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd"
+ + "|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e04\u0e2d\u0e21|\u0e44\u0e17\u0e22"
+ + "|\u10d2\u10d4|\u307f\u3093\u306a|\u30b0\u30fc\u30b0\u30eb|\u30b3\u30e0|\u4e16\u754c"
+ + "|\u4e2d\u4fe1|\u4e2d\u56fd|\u4e2d\u570b|\u4e2d\u6587\u7f51|\u4f01\u4e1a|\u4f5b\u5c71"
+ + "|\u4fe1\u606f|\u5065\u5eb7|\u516b\u5366|\u516c\u53f8|\u516c\u76ca|\u53f0\u6e7e|\u53f0\u7063"
+ + "|\u5546\u57ce|\u5546\u5e97|\u5546\u6807|\u5728\u7ebf|\u5927\u62ff|\u5a31\u4e50|\u5de5\u884c"
+ + "|\u5e7f\u4e1c|\u6148\u5584|\u6211\u7231\u4f60|\u624b\u673a|\u653f\u52a1|\u653f\u5e9c"
+ + "|\u65b0\u52a0\u5761|\u65b0\u95fb|\u65f6\u5c1a|\u673a\u6784|\u6de1\u9a6c\u9521|\u6e38\u620f"
+ + "|\u70b9\u770b|\u79fb\u52a8|\u7ec4\u7ec7\u673a\u6784|\u7f51\u5740|\u7f51\u5e97|\u7f51\u7edc"
+ + "|\u8c37\u6b4c|\u96c6\u56e2|\u98de\u5229\u6d66|\u9910\u5385|\u9999\u6e2f|\ub2f7\ub137"
+ + "|\ub2f7\ucef4|\uc0bc\uc131|\ud55c\uad6d|xbox"
+ + "|xerox|xin|xn\\-\\-11b4c3d|xn\\-\\-1qqw23a|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g"
+ + "|xn\\-\\-3e0b707e|xn\\-\\-3pxu8k|xn\\-\\-42c2d9a|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4gbrim"
+ + "|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks"
+ + "|xn\\-\\-80ao21a|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-90a3ac|xn\\-\\-90ais|xn\\-\\-9dbq2a"
+ + "|xn\\-\\-9et52u|xn\\-\\-b4w605ferd|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd"
+ + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-efvy88h"
+ + "|xn\\-\\-estv75g|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s"
+ + "|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-gecrj9c"
+ + "|xn\\-\\-h2brj9c|xn\\-\\-hxt814e|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i"
+ + "|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d"
+ + "|xn\\-\\-kput3i|xn\\-\\-l1acc|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgb9awbf|xn\\-\\-mgba3a3ejt"
+ + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e"
+ + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbpl2fh|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab"
+ + "|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema"
+ + "|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh"
+ + "|xn\\-\\-pssy2u|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-s9brj9c"
+ + "|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb"
+ + "|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv|xn\\-\\-vuq861b|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a"
+ + "|xn\\-\\-xhq521b|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-y9a3aq|xn\\-\\-yfro4i67o"
+ + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xperia|xxx|xyz)"
+ + "|(?:yachts|yamaxun|yandex|yodobashi|yoga|yokohama|youtube|y[et])"
+ + "|(?:zara|zip|zone|zuerich|z[amw]))")
+
+ /**
+ * Valid UCS characters defined in RFC 3987. Excludes space characters.
+ */
+ private const val UCS_CHAR = "[" +
+ "\u00A0-\uD7FF" +
+ "\uF900-\uFDCF" +
+ "\uFDF0-\uFFEF" +
+ "\uD800\uDC00-\uD83F\uDFFD" +
+ "\uD840\uDC00-\uD87F\uDFFD" +
+ "\uD880\uDC00-\uD8BF\uDFFD" +
+ "\uD8C0\uDC00-\uD8FF\uDFFD" +
+ "\uD900\uDC00-\uD93F\uDFFD" +
+ "\uD940\uDC00-\uD97F\uDFFD" +
+ "\uD980\uDC00-\uD9BF\uDFFD" +
+ "\uD9C0\uDC00-\uD9FF\uDFFD" +
+ "\uDA00\uDC00-\uDA3F\uDFFD" +
+ "\uDA40\uDC00-\uDA7F\uDFFD" +
+ "\uDA80\uDC00-\uDABF\uDFFD" +
+ "\uDAC0\uDC00-\uDAFF\uDFFD" +
+ "\uDB00\uDC00-\uDB3F\uDFFD" +
+ "\uDB44\uDC00-\uDB7F\uDFFD" +
+ "&&[^\u00A0[\u2000-\u200A]\u2028\u2029\u202F\u3000]]"
+
+ /**
+ * Valid characters for IRI label defined in RFC 3987.
+ */
+ private const val LABEL_CHAR = "a-zA-Z0-9$UCS_CHAR"
+
+ /**
+ * Valid characters for IRI TLD defined in RFC 3987.
+ */
+ private const val TLD_CHAR = "a-zA-Z$UCS_CHAR"
+
+ /**
+ * RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets.
+ */
+ private const val IRI_LABEL = "[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "_\\-]{0,61}[" + LABEL_CHAR + "]){0,1}"
+
+ /**
+ * RFC 3492 references RFC 1034 and limits Punycode algorithm output to 63 characters.
+ */
+ private const val PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w"
+ private const val TLD = "($PUNYCODE_TLD|[${TLD_CHAR}]{2,63})"
+ private const val HOST_NAME = "(${IRI_LABEL}\\.)+$TLD"
+ private const val DOMAIN_NAME = "($HOST_NAME|${IP_ADDRESS})"
+ private const val PROTOCOL = "(?i:http|https|rtsp)://"
+
+ /* A word boundary or end of input. This is to stop foo.sure from matching as foo.su */
+ private const val WORD_BOUNDARY = "(?:\\b|$|^)"
+ private const val USER_INFO = ("(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@")
+ private const val PORT_NUMBER = "\\:\\d{1,5}"
+ private const val PATH_AND_QUERY = ("[/\\?](?:(?:[" + LABEL_CHAR
+ + ";/\\?:@&=#~" // plus optional query params
+ + "\\-\\.\\+!\\*'\\(\\),_\\$])|(?:%[a-fA-F0-9]{2}))*")
+
+ /**
+ * Regular expression that matches known TLDs and punycode TLDs
+ */
+ private const val STRICT_TLD = "(?:$IANA_TOP_LEVEL_DOMAINS|$PUNYCODE_TLD)"
+
+ /**
+ * Regular expression that matches host names using [.STRICT_TLD]
+ */
+ private const val STRICT_HOST_NAME = ("(?:(?:" + IRI_LABEL + "\\.)+"
+ + STRICT_TLD + ")")
+
+ /**
+ * Regular expression that matches domain names using either [.STRICT_HOST_NAME] or
+ * [.IP_ADDRESS]
+ */
+ private const val STRICT_DOMAIN_NAME = ("(?:$STRICT_HOST_NAME|$IP_ADDRESS)")
+
+ /**
+ * Regular expression that matches domain names without a TLD
+ */
+ private const val RELAXED_DOMAIN_NAME = "(?:(?:${IRI_LABEL}(?:\\.(?=\\S))?)+|${IP_ADDRESS})"
+
+ /**
+ * Regular expression to match strings that do not start with a supported protocol. The TLDs
+ * are expected to be one of the known TLDs.
+ */
+ private const val WEB_URL_WITHOUT_PROTOCOL = ("("
+ + WORD_BOUNDARY
+ + "(?
Date: Thu, 13 Feb 2025 23:08:40 +0100
Subject: [PATCH 25/35] Make adjustments and add convenience functions for
relay pool management.
---
.../kotlin/ballast/nostr/relay/RelayPool.kt | 28 ++++++++++++++++---
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
index d0d7dff..1c722d6 100644
--- a/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
@@ -5,16 +5,18 @@ import kotlin.jvm.JvmStatic
class RelayPool {
- private var relayList: MutableList
+ private val relayList: MutableList = mutableListOf()
constructor(){
- relayList = getDefaultRelays().toMutableList()
+ getDefaultRelays().forEach {
+ relayList.add(it)
+ }
}
constructor(relays: List) : this() {
- this.relayList = relays as MutableList
+ relays.forEach { relayList.add(it) }
}
- fun getRelays() = if (relayList.isEmpty()) getDefaultRelays() else relayList.toList()
+ fun getRelays() = relayList.toList()
fun addRelay(relay: Relay) {
if (relayList.add(relay))
@@ -28,10 +30,23 @@ class RelayPool {
}
}
+ fun addRelays(relays: Collection) {
+ relays.forEach { relayList.add(it) }
+ }
+
+ fun addRelayList(listOfRelays: Collection) {
+ val relayRefs = listOfRelays.map { Relay(it) }
+ addRelays(relayRefs)
+ }
+
fun removeRelay(relay: Relay) {
relayList.remove(relay)
}
+ fun clearPool() {
+ relayList.clear()
+ }
+
companion object {
fun fromUrls(vararg relayUris: String): RelayPool {
@@ -39,6 +54,11 @@ class RelayPool {
return RelayPool(relayList)
}
+ fun fromUrls(urlList: Collection): RelayPool {
+ val relayList = urlList.map { Relay(it) }
+ return RelayPool(relayList)
+ }
+
@JvmStatic
fun getDefaultRelays(): List = listOf(
Relay("wss://nostr-pub.wellorder.net"),
From 9bd1806589cc5331fb0d64c31ac03f518765bca2 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Thu, 13 Feb 2025 23:12:06 +0100
Subject: [PATCH 26/35] Add new API: clearRelayPool().
---
.../src/commonMain/kotlin/ballast/net/NostrService.kt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt b/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
index 9a914bf..b079b65 100644
--- a/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
@@ -20,7 +20,7 @@ import kotlin.coroutines.CoroutineContext
class NostrService(
- private val relayPool: RelayPool = RelayPool(),
+ val relayPool: RelayPool = RelayPool(),
private val client: HttpClient = httpClient { install(WebSockets){} }
): CoroutineScope {
private val serviceDispatcher = Dispatchers.IO.limitedParallelism(
@@ -226,6 +226,10 @@ class NostrService(
return results
}
+ fun clearRelayPool() {
+ relayPool.clearPool()
+ }
+
fun stopService(){
if (this.isActive) this.serviceDispatcher.cancel()
}
From 98cbeb3e4cffeb52f79bb91a1fe9eb281cf0991f Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 00:11:16 +0100
Subject: [PATCH 27/35] Use hex conversion for Uuid in singleRequestFilter,
until Kotlin UUID is ready(?).
---
.../kotlin/ballast/nostr/client/ClientMessage.kt | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
index 4b9f70e..d5976f1 100644
--- a/ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
@@ -1,5 +1,8 @@
package ballast.nostr.client
+import ballast.crypto.toHexString
+import ballast.nostr.Event
+import ballast.nostr.NostrFilter
import com.benasher44.uuid.bytes
import com.benasher44.uuid.uuid4
import kotlinx.serialization.ExperimentalSerializationApi
@@ -12,8 +15,6 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*
-import ballast.nostr.Event
-import ballast.nostr.NostrFilter
@Serializable(with = ClientMessage.MessageSerializer::class)
sealed class ClientMessage(open val messageType: String){
@@ -114,7 +115,7 @@ open class RequestMessage(
companion object {
fun singleFilterRequest(
- subscriptionId: String = uuid4().bytes.decodeToString().substring(0, 5),
+ subscriptionId: String = uuid4().bytes.toHexString().substring(0, 5),
filter: NostrFilter
): RequestMessage {
return RequestMessage(messageType = "REQ", subscriptionId, listOf(filter))
From 52d443ad74c055bb4b05e913ae8f649895b5f036 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 00:19:18 +0100
Subject: [PATCH 28/35] Introduce new API: getMetadataFor(profile, relays). Fix
requestFromRelay().
---
.../kotlin/ballast/net/NostrService.kt | 48 +++++++++++++------
1 file changed, 33 insertions(+), 15 deletions(-)
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt b/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
index b079b65..2ffbfba 100644
--- a/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
@@ -5,7 +5,9 @@ import ballast.nostr.Event
import ballast.nostr.client.ClientMessage
import ballast.nostr.client.RequestMessage
import ballast.nostr.deserializedEvent
+import ballast.nostr.EventKind
import ballast.nostr.eventMapper
+import ballast.nostr.NostrFilter
import ballast.nostr.relay.*
import io.ktor.client.*
import io.ktor.client.plugins.websocket.*
@@ -96,7 +98,7 @@ class NostrService(
// }
}
- private suspend fun requestFromRelay(
+ private fun requestFromRelay(
requestMessage: RequestMessage,
relay: Relay,
onRelayMessage: suspend (Relay, RelayMessage) -> Unit,
@@ -104,23 +106,25 @@ class NostrService(
) {
val requestJson = eventMapper.encodeToString(requestMessage)
- println("Coroutine Scope @ ${relay.relayURI}")
- try {
- client.webSocket(urlString = relay.relayURI) {
- send(requestJson)
+ launch {
+ println("Coroutine Scope @ ${relay.relayURI}")
+ try {
+ client.webSocket(urlString = relay.relayURI) {
+ send(requestJson)
- for (frame in incoming) {
- val received = (frame as Frame.Text).readText()
- val receivedMessage = eventMapper.decodeFromString(received)
- onRelayMessage(relay, receivedMessage)
+ for (frame in incoming) {
+ val received = (frame as Frame.Text).readText()
+ val receivedMessage = eventMapper.decodeFromString(received)
+ onRelayMessage(relay, receivedMessage)
+ }
}
+ } catch (e: kotlinx.io.IOException) {
+ onRequestError(relay, e)
+ } catch (err: Exception) {
+ onRequestError(relay, err)
+ } catch (t: Throwable) {
+ onRequestError(relay, t)
}
- } catch (e: kotlinx.io.IOException) {
- onRequestError(relay, e)
- } catch (err: Exception) {
- onRequestError(relay, err)
- } catch (t: Throwable) {
- onRequestError(relay, t)
}
}
@@ -226,6 +230,20 @@ class NostrService(
return results
}
+ suspend fun getMetadataFor(profileHex: String, preferredRelays: List): Event {
+ val profileRequest = RequestMessage.singleFilterRequest(
+ filter = NostrFilter.newFilter()
+ .kinds(EventKind.METADATA.kind)
+ .authors(profileHex)
+ .limit(1)
+ .build()
+ )
+ val potentialResults = if (preferredRelays.isEmpty())
+ requestWithResult(profileRequest) else requestWithResult(profileRequest, preferredRelays.map { Relay(it) })
+
+ return potentialResults.maxBy { it.creationDate }
+ }
+
fun clearRelayPool() {
relayPool.clearPool()
}
From 63e75a7f6a65abc97877607890a061758f0e4efb Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 00:58:20 +0100
Subject: [PATCH 29/35] Move to new name: Rhodium
---
build.gradle.kts | 8 +--
{ballast-core => rhodium-core}/.gitignore | 0
.../build.gradle.kts | 2 +-
.../android/ExampleInstrumentedTest.kt | 0
.../src/androidMain/AndroidManifest.xml | 0
.../kotlin/ballast/android/NostrLifeCycle.kt | 56 +++++++++++++++++++
.../kotlin/ballast/android/ExampleUnitTest.kt | 0
.../ballast/crypto/CryptoProvider.apple.kt | 0
.../kotlin/ballast/net/HttpClient.apple.kt | 0
.../crypto/CryptoProvider.commonJvm.kt | 0
.../ballast/net/HttpClient.commonJvm.kt | 0
.../kotlin/ballast/DateTimeUtils.kt | 0
.../kotlin/ballast/crypto/CryptoProvider.kt | 0
.../kotlin/ballast/crypto/CryptoUtils.kt | 0
.../kotlin/ballast/net/HttpClient.kt | 0
.../kotlin/ballast/net/NostrService.kt | 0
.../kotlin/ballast/net/NostrUtils.kt | 0
.../commonMain/kotlin/ballast/net/UrlUtil.kt | 0
.../commonMain/kotlin/ballast/nostr/Event.kt | 0
.../kotlin/ballast/nostr/EventExt.kt | 0
.../commonMain/kotlin/ballast/nostr/Events.kt | 0
.../kotlin/ballast/nostr/NostrErrors.kt | 0
.../kotlin/ballast/nostr/NostrFilter.kt | 0
.../commonMain/kotlin/ballast/nostr/Tag.kt | 0
.../ballast/nostr/client/ClientMessage.kt | 0
.../kotlin/ballast/nostr/relay/Relay.kt | 0
.../ballast/nostr/relay/RelayMessage.kt | 0
.../kotlin/ballast/nostr/relay/RelayPool.kt | 0
.../kotlin/ballast/crypto/CryptoUtilsTest.kt | 0
.../kotlin/ballast/nostr/EventTests.kt | 0
.../kotlin/ballast/nostr/NostrFilterTest.kt | 0
.../kotlin/ballast/nostr/NostrTests.kt | 0
.../nostr/client/ClientMessageTests.kt | 0
.../ballast/nostr/relay/RelayMessageTests.kt | 0
.../resources/test_subscriptions_data.txt | 0
.../src/linuxMain/cinterop/libs.def | 0
rhodium-core/src/linuxMain/kotlin/Entry.kt | 5 ++
.../ballast/crypto/CryptoProvider.linux.kt | 0
.../kotlin/ballast/net/HttpClient.linux.kt | 0
settings.gradle.kts | 4 +-
40 files changed, 68 insertions(+), 7 deletions(-)
rename {ballast-core => rhodium-core}/.gitignore (100%)
rename {ballast-core => rhodium-core}/build.gradle.kts (99%)
rename {ballast-core => rhodium-core}/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt (100%)
rename {ballast-core => rhodium-core}/src/androidMain/AndroidManifest.xml (100%)
create mode 100644 rhodium-core/src/androidMain/kotlin/ballast/android/NostrLifeCycle.kt
rename {ballast-core => rhodium-core}/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt (100%)
rename {ballast-core => rhodium-core}/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt (100%)
rename {ballast-core => rhodium-core}/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt (100%)
rename {ballast-core => rhodium-core}/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt (100%)
rename {ballast-core => rhodium-core}/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/DateTimeUtils.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/net/HttpClient.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/net/NostrService.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/net/NostrUtils.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/net/UrlUtil.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/Event.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/EventExt.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/Events.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/Tag.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt (100%)
rename {ballast-core => rhodium-core}/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt (100%)
rename {ballast-core => rhodium-core}/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt (100%)
rename {ballast-core => rhodium-core}/src/commonTest/kotlin/ballast/nostr/EventTests.kt (100%)
rename {ballast-core => rhodium-core}/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt (100%)
rename {ballast-core => rhodium-core}/src/commonTest/kotlin/ballast/nostr/NostrTests.kt (100%)
rename {ballast-core => rhodium-core}/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt (100%)
rename {ballast-core => rhodium-core}/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt (100%)
rename {ballast-core => rhodium-core}/src/commonTest/resources/test_subscriptions_data.txt (100%)
rename {ballast-core => rhodium-core}/src/linuxMain/cinterop/libs.def (100%)
create mode 100644 rhodium-core/src/linuxMain/kotlin/Entry.kt
rename {ballast-core => rhodium-core}/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt (100%)
rename {ballast-core => rhodium-core}/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt (100%)
diff --git a/build.gradle.kts b/build.gradle.kts
index e053c0b..9837945 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -43,14 +43,14 @@ allprojects {
signAllPublications()
}
- coordinates(group.toString(), "ballast", version.toString())
+ coordinates(group.toString(), "rhodium", version.toString())
// configure(KotlinMultiplatform(
// javadocJar = JavadocJar.Javadoc(),
// sourcesJar = true
// ))
pom {
- name = "Ballast"
+ name = "Rhodium"
description = " A Kotlin Multiplatform library for Nostr"
url = "https://github.com/KotlinGeekDev/Ballast"
@@ -71,8 +71,8 @@ allprojects {
}
scm {
- connection = "scm:git:git://github.com/KotlinGeekDev/Ballast.git"
- url = "https://github.com/KotlinGeekDev/Ballast"
+ connection = "scm:git:git://github.com/KotlinGeekDev/Rhodium.git"
+ url = "https://github.com/KotlinGeekDev/Rhodium"
}
}
}
diff --git a/ballast-core/.gitignore b/rhodium-core/.gitignore
similarity index 100%
rename from ballast-core/.gitignore
rename to rhodium-core/.gitignore
diff --git a/ballast-core/build.gradle.kts b/rhodium-core/build.gradle.kts
similarity index 99%
rename from ballast-core/build.gradle.kts
rename to rhodium-core/build.gradle.kts
index ef2e2f8..d299d38 100644
--- a/ballast-core/build.gradle.kts
+++ b/rhodium-core/build.gradle.kts
@@ -201,7 +201,7 @@ kotlin {
}
android {
- namespace = "io.github.kotlingeekdev.ballast.android"
+ namespace = "io.github.kotlingeekdev.rhodium.android"
compileSdk = 34
defaultConfig {
minSdk = 21
diff --git a/ballast-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt b/rhodium-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt
similarity index 100%
rename from ballast-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt
rename to rhodium-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt
diff --git a/ballast-core/src/androidMain/AndroidManifest.xml b/rhodium-core/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from ballast-core/src/androidMain/AndroidManifest.xml
rename to rhodium-core/src/androidMain/AndroidManifest.xml
diff --git a/rhodium-core/src/androidMain/kotlin/ballast/android/NostrLifeCycle.kt b/rhodium-core/src/androidMain/kotlin/ballast/android/NostrLifeCycle.kt
new file mode 100644
index 0000000..4a22231
--- /dev/null
+++ b/rhodium-core/src/androidMain/kotlin/ballast/android/NostrLifeCycle.kt
@@ -0,0 +1,56 @@
+package ballast.android
+
+import androidx.lifecycle.*
+import androidx.lifecycle.Lifecycle.State
+
+class NostrLifeCycle: LifecycleOwner {
+ private var lifecycleState = State.INITIALIZED
+ private val lifecycleRegistry = LifecycleRegistry(this)
+
+ override val lifecycle: Lifecycle = lifecycleRegistry
+
+ fun currentState(): Lifecycle.State {
+ return lifecycleState
+ }
+
+
+ fun changeState(newState: Lifecycle.State){
+ lifecycleState = newState
+ }
+
+
+ inner class NostrEventObserver() : DefaultLifecycleObserver, LifecycleEventObserver {
+ override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
+ val state = source.lifecycle.currentState
+ this@NostrLifeCycle.changeState(state)
+ this@NostrLifeCycle.lifecycleRegistry.handleLifecycleEvent(event)
+ }
+
+ override fun onCreate(owner: LifecycleOwner) {
+ this@NostrLifeCycle.lifecycleRegistry.addObserver(this)
+ super.onCreate(owner)
+ }
+
+ override fun onStart(owner: LifecycleOwner) {
+ super.onStart(owner)
+ }
+
+ override fun onResume(owner: LifecycleOwner) {
+ super.onResume(owner)
+ }
+
+ override fun onPause(owner: LifecycleOwner) {
+ super.onPause(owner)
+ }
+
+ override fun onStop(owner: LifecycleOwner) {
+ super.onStop(owner)
+ }
+
+ override fun onDestroy(owner: LifecycleOwner) {
+ this@NostrLifeCycle.lifecycleRegistry.removeObserver(this)
+ super.onDestroy(owner)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/ballast-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt b/rhodium-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt
similarity index 100%
rename from ballast-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt
rename to rhodium-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt
diff --git a/ballast-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt b/rhodium-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt
similarity index 100%
rename from ballast-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt
rename to rhodium-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt
diff --git a/ballast-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt b/rhodium-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt
similarity index 100%
rename from ballast-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt
rename to rhodium-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt
diff --git a/ballast-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt b/rhodium-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt
similarity index 100%
rename from ballast-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt
rename to rhodium-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt
diff --git a/ballast-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt b/rhodium-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt
similarity index 100%
rename from ballast-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt
rename to rhodium-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt b/rhodium-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt b/rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt b/rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/HttpClient.kt b/rhodium-core/src/commonMain/kotlin/ballast/net/HttpClient.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/net/HttpClient.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/net/HttpClient.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt b/rhodium-core/src/commonMain/kotlin/ballast/net/NostrService.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/net/NostrService.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/net/NostrService.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt b/rhodium-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt b/rhodium-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/Event.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/Event.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/Event.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/Event.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/Events.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/Events.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/Events.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt b/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
similarity index 100%
rename from ballast-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
rename to rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
diff --git a/ballast-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt b/rhodium-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt
similarity index 100%
rename from ballast-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt
rename to rhodium-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt
diff --git a/ballast-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt b/rhodium-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt
similarity index 100%
rename from ballast-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt
rename to rhodium-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt
diff --git a/ballast-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt b/rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt
similarity index 100%
rename from ballast-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt
rename to rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt
diff --git a/ballast-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt b/rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt
similarity index 100%
rename from ballast-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt
rename to rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt
diff --git a/ballast-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt b/rhodium-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt
similarity index 100%
rename from ballast-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt
rename to rhodium-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt
diff --git a/ballast-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt b/rhodium-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt
similarity index 100%
rename from ballast-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt
rename to rhodium-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt
diff --git a/ballast-core/src/commonTest/resources/test_subscriptions_data.txt b/rhodium-core/src/commonTest/resources/test_subscriptions_data.txt
similarity index 100%
rename from ballast-core/src/commonTest/resources/test_subscriptions_data.txt
rename to rhodium-core/src/commonTest/resources/test_subscriptions_data.txt
diff --git a/ballast-core/src/linuxMain/cinterop/libs.def b/rhodium-core/src/linuxMain/cinterop/libs.def
similarity index 100%
rename from ballast-core/src/linuxMain/cinterop/libs.def
rename to rhodium-core/src/linuxMain/cinterop/libs.def
diff --git a/rhodium-core/src/linuxMain/kotlin/Entry.kt b/rhodium-core/src/linuxMain/kotlin/Entry.kt
new file mode 100644
index 0000000..753f677
--- /dev/null
+++ b/rhodium-core/src/linuxMain/kotlin/Entry.kt
@@ -0,0 +1,5 @@
+import kotlinx.coroutines.runBlocking
+
+fun main() = runBlocking {
+ ballast.main()
+}
\ No newline at end of file
diff --git a/ballast-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt b/rhodium-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt
similarity index 100%
rename from ballast-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt
rename to rhodium-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt
diff --git a/ballast-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt b/rhodium-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt
similarity index 100%
rename from ballast-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt
rename to rhodium-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 9132f08..50999d7 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -13,6 +13,6 @@ dependencyResolutionManagement {
}
}
-rootProject.name = "ballast"
-include("ballast-core")
+rootProject.name = "rhodium"
+include("rhodium-core")
//include(":kostr-android")
From ce0955f82cc150f9e2ff89665e097faedafdb545 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 09:33:46 +0100
Subject: [PATCH 30/35] Prepare new version: v1.0-beta-08. Adjust README to new
version and name.
---
README.md | 12 +++++-----
build.gradle.kts | 2 +-
.../android/ExampleInstrumentedTest.kt | 2 +-
.../android/NostrLifeCycle.kt | 2 +-
.../android/ExampleUnitTest.kt | 2 +-
.../crypto/CryptoProvider.apple.kt | 2 +-
.../net/HttpClient.apple.kt | 2 +-
.../crypto/CryptoProvider.commonJvm.kt | 2 +-
.../net/HttpClient.commonJvm.kt | 2 +-
.../{ballast => rhodium}/DateTimeUtils.kt | 2 +-
.../crypto/CryptoProvider.kt | 2 +-
.../crypto/CryptoUtils.kt | 2 +-
.../{ballast => rhodium}/net/HttpClient.kt | 2 +-
.../{ballast => rhodium}/net/NostrService.kt | 22 +++++++++----------
.../{ballast => rhodium}/net/NostrUtils.kt | 8 +++----
.../{ballast => rhodium}/net/UrlUtil.kt | 2 +-
.../{ballast => rhodium}/nostr/Event.kt | 12 +++++++---
.../{ballast => rhodium}/nostr/EventExt.kt | 4 ++--
.../{ballast => rhodium}/nostr/Events.kt | 10 ++++-----
.../{ballast => rhodium}/nostr/NostrErrors.kt | 2 +-
.../{ballast => rhodium}/nostr/NostrFilter.kt | 2 +-
.../kotlin/{ballast => rhodium}/nostr/Tag.kt | 2 +-
.../nostr/client/ClientMessage.kt | 8 +++----
.../{ballast => rhodium}/nostr/relay/Relay.kt | 2 +-
.../nostr/relay/RelayMessage.kt | 4 ++--
.../nostr/relay/RelayPool.kt | 4 ++--
.../crypto/CryptoUtilsTest.kt | 2 +-
.../{ballast => rhodium}/nostr/EventTests.kt | 2 +-
.../nostr/NostrFilterTest.kt | 4 ++--
.../{ballast => rhodium}/nostr/NostrTests.kt | 2 +-
.../nostr/client/ClientMessageTests.kt | 6 ++---
.../nostr/relay/RelayMessageTests.kt | 2 +-
rhodium-core/src/linuxMain/kotlin/Entry.kt | 2 +-
.../crypto/CryptoProvider.linux.kt | 2 +-
.../net/HttpClient.linux.kt | 2 +-
35 files changed, 74 insertions(+), 68 deletions(-)
rename rhodium-core/src/androidInstrumentedTest/kotlin/{ballast => rhodium}/android/ExampleInstrumentedTest.kt (96%)
rename rhodium-core/src/androidMain/kotlin/{ballast => rhodium}/android/NostrLifeCycle.kt (98%)
rename rhodium-core/src/androidUnitTest/kotlin/{ballast => rhodium}/android/ExampleUnitTest.kt (94%)
rename rhodium-core/src/appleMain/kotlin/{ballast => rhodium}/crypto/CryptoProvider.apple.kt (93%)
rename rhodium-core/src/appleMain/kotlin/{ballast => rhodium}/net/HttpClient.apple.kt (91%)
rename rhodium-core/src/commonJvmMain/kotlin/{ballast => rhodium}/crypto/CryptoProvider.commonJvm.kt (95%)
rename rhodium-core/src/commonJvmMain/kotlin/{ballast => rhodium}/net/HttpClient.commonJvm.kt (89%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/DateTimeUtils.kt (98%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/crypto/CryptoProvider.kt (90%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/crypto/CryptoUtils.kt (99%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/net/HttpClient.kt (84%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/net/NostrService.kt (96%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/net/NostrUtils.kt (95%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/net/UrlUtil.kt (99%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/Event.kt (95%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/EventExt.kt (98%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/Events.kt (96%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/NostrErrors.kt (98%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/NostrFilter.kt (99%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/Tag.kt (99%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/client/ClientMessage.kt (98%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/relay/Relay.kt (89%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/relay/RelayMessage.kt (99%)
rename rhodium-core/src/commonMain/kotlin/{ballast => rhodium}/nostr/relay/RelayPool.kt (96%)
rename rhodium-core/src/commonTest/kotlin/{ballast => rhodium}/crypto/CryptoUtilsTest.kt (98%)
rename rhodium-core/src/commonTest/kotlin/{ballast => rhodium}/nostr/EventTests.kt (99%)
rename rhodium-core/src/commonTest/kotlin/{ballast => rhodium}/nostr/NostrFilterTest.kt (98%)
rename rhodium-core/src/commonTest/kotlin/{ballast => rhodium}/nostr/NostrTests.kt (99%)
rename rhodium-core/src/commonTest/kotlin/{ballast => rhodium}/nostr/client/ClientMessageTests.kt (98%)
rename rhodium-core/src/commonTest/kotlin/{ballast => rhodium}/nostr/relay/RelayMessageTests.kt (98%)
rename rhodium-core/src/linuxMain/kotlin/{ballast => rhodium}/crypto/CryptoProvider.linux.kt (93%)
rename rhodium-core/src/linuxMain/kotlin/{ballast => rhodium}/net/HttpClient.linux.kt (90%)
diff --git a/README.md b/README.md
index d89041d..562ad5f 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Kostr
+# Rhodium
[](https://kotlinlang.org)
[](https://search.maven.org/search?q=g:io.github.kotlingeekdev)
@@ -25,7 +25,7 @@ You can include the library from either Maven Central or Jitpack.
You can include the library in the common source set like this:
```kotlin
dependencies {
- implementation("io.github.kotlingeekdev:ballast:1.0-beta-07")
+ implementation("io.github.kotlingeekdev:rhodium:1.0-beta-08")
}
```
@@ -73,7 +73,7 @@ then, in your module's `build.gradle(.kts)`, you need to add:
// build.gradle.kts
dependencies {
//...
- implementation("com.github.KotlinGeekDev.Ballast:ballast:1.0-beta-07")
+ implementation("com.github.KotlinGeekDev.Rhodium:rhodium:1.0-beta-08")
}
@@ -83,15 +83,15 @@ If you're including it in an Android app, you can just add:
// app/build.gradle.kts
dependencies {
//...
- implementation("com.github.KotlinGeekDev.Ballast:ballast-android:1.0-beta-07")
+ implementation("com.github.KotlinGeekDev.Rhodium:rhodium-android:1.0-beta-08")
}
```
## Usage
When publishing an event, or making a subscription/close request to a relay,
-[`ClientMessage`](kostr-core/src/commonMain/kotlin/ktnostr/nostr/client/ClientMessage.kt) is used to encode the request/event,
-and anything sent by a relay is encoded as a [`RelayMessage`](kostr-core/src/commonMain/kotlin/ktnostr/nostr/relay/RelayMessage.kt).
+[`ClientMessage`](rhodium-core/src/commonMain/kotlin/rhodium/nostr/client/ClientMessage.kt) is used to encode the request/event,
+and anything sent by a relay is encoded as a [`RelayMessage`](rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/RelayMessage.kt).
Relays can be configured using a `RelayPool`,
and actual communication with relays is done with the `NostrService`.
You can setup the NostrService with/without a custom relay pool as follows:
diff --git a/build.gradle.kts b/build.gradle.kts
index 9837945..5351c16 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -31,7 +31,7 @@ allprojects {
val isJitpack = System.getenv("JITPACK") == "true"
group = "io.github.kotlingeekdev"
- version = "1.0-beta-07"
+ version = "1.0-beta-08"
// val javadocJar = tasks.register("javadocJar") {
// archiveClassifier.set("javadoc")
diff --git a/rhodium-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt b/rhodium-core/src/androidInstrumentedTest/kotlin/rhodium/android/ExampleInstrumentedTest.kt
similarity index 96%
rename from rhodium-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt
rename to rhodium-core/src/androidInstrumentedTest/kotlin/rhodium/android/ExampleInstrumentedTest.kt
index de71c84..5531225 100644
--- a/rhodium-core/src/androidInstrumentedTest/kotlin/ballast/android/ExampleInstrumentedTest.kt
+++ b/rhodium-core/src/androidInstrumentedTest/kotlin/rhodium/android/ExampleInstrumentedTest.kt
@@ -1,4 +1,4 @@
-package ballast.android
+package rhodium.android
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
diff --git a/rhodium-core/src/androidMain/kotlin/ballast/android/NostrLifeCycle.kt b/rhodium-core/src/androidMain/kotlin/rhodium/android/NostrLifeCycle.kt
similarity index 98%
rename from rhodium-core/src/androidMain/kotlin/ballast/android/NostrLifeCycle.kt
rename to rhodium-core/src/androidMain/kotlin/rhodium/android/NostrLifeCycle.kt
index 4a22231..799cfdd 100644
--- a/rhodium-core/src/androidMain/kotlin/ballast/android/NostrLifeCycle.kt
+++ b/rhodium-core/src/androidMain/kotlin/rhodium/android/NostrLifeCycle.kt
@@ -1,4 +1,4 @@
-package ballast.android
+package rhodium.android
import androidx.lifecycle.*
import androidx.lifecycle.Lifecycle.State
diff --git a/rhodium-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt b/rhodium-core/src/androidUnitTest/kotlin/rhodium/android/ExampleUnitTest.kt
similarity index 94%
rename from rhodium-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt
rename to rhodium-core/src/androidUnitTest/kotlin/rhodium/android/ExampleUnitTest.kt
index 399bada..0f4c1bc 100644
--- a/rhodium-core/src/androidUnitTest/kotlin/ballast/android/ExampleUnitTest.kt
+++ b/rhodium-core/src/androidUnitTest/kotlin/rhodium/android/ExampleUnitTest.kt
@@ -1,4 +1,4 @@
-package ballast.android
+package rhodium.android
import org.junit.Assert.assertEquals
import org.junit.Test
diff --git a/rhodium-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt b/rhodium-core/src/appleMain/kotlin/rhodium/crypto/CryptoProvider.apple.kt
similarity index 93%
rename from rhodium-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt
rename to rhodium-core/src/appleMain/kotlin/rhodium/crypto/CryptoProvider.apple.kt
index 05ff28b..1de2af5 100644
--- a/rhodium-core/src/appleMain/kotlin/ballast/crypto/CryptoProvider.apple.kt
+++ b/rhodium-core/src/appleMain/kotlin/rhodium/crypto/CryptoProvider.apple.kt
@@ -1,4 +1,4 @@
-package ballast.crypto
+package rhodium.crypto
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.providers.apple.Apple
diff --git a/rhodium-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt b/rhodium-core/src/appleMain/kotlin/rhodium/net/HttpClient.apple.kt
similarity index 91%
rename from rhodium-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt
rename to rhodium-core/src/appleMain/kotlin/rhodium/net/HttpClient.apple.kt
index 03ae645..76454f1 100644
--- a/rhodium-core/src/appleMain/kotlin/ballast/net/HttpClient.apple.kt
+++ b/rhodium-core/src/appleMain/kotlin/rhodium/net/HttpClient.apple.kt
@@ -1,4 +1,4 @@
-package ballast.net
+package rhodium.net
import io.ktor.client.*
import io.ktor.client.engine.darwin.*
diff --git a/rhodium-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt b/rhodium-core/src/commonJvmMain/kotlin/rhodium/crypto/CryptoProvider.commonJvm.kt
similarity index 95%
rename from rhodium-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt
rename to rhodium-core/src/commonJvmMain/kotlin/rhodium/crypto/CryptoProvider.commonJvm.kt
index 07b32d9..8ade3b1 100644
--- a/rhodium-core/src/commonJvmMain/kotlin/ballast/crypto/CryptoProvider.commonJvm.kt
+++ b/rhodium-core/src/commonJvmMain/kotlin/rhodium/crypto/CryptoProvider.commonJvm.kt
@@ -1,4 +1,4 @@
-package ballast.crypto
+package rhodium.crypto
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.providers.jdk.JDK
diff --git a/rhodium-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt b/rhodium-core/src/commonJvmMain/kotlin/rhodium/net/HttpClient.commonJvm.kt
similarity index 89%
rename from rhodium-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt
rename to rhodium-core/src/commonJvmMain/kotlin/rhodium/net/HttpClient.commonJvm.kt
index 243e415..17ebed3 100644
--- a/rhodium-core/src/commonJvmMain/kotlin/ballast/net/HttpClient.commonJvm.kt
+++ b/rhodium-core/src/commonJvmMain/kotlin/rhodium/net/HttpClient.commonJvm.kt
@@ -1,4 +1,4 @@
-package ballast.net
+package rhodium.net
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt b/rhodium-core/src/commonMain/kotlin/rhodium/DateTimeUtils.kt
similarity index 98%
rename from rhodium-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/DateTimeUtils.kt
index 3b17d47..4479a78 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/DateTimeUtils.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/DateTimeUtils.kt
@@ -1,4 +1,4 @@
-package ballast
+package rhodium
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/CryptoProvider.kt
similarity index 90%
rename from rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/crypto/CryptoProvider.kt
index f7562c1..00a71b6 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoProvider.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/CryptoProvider.kt
@@ -1,4 +1,4 @@
-package ballast.crypto
+package rhodium.crypto
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.random.CryptographyRandom
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/CryptoUtils.kt
similarity index 99%
rename from rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/crypto/CryptoUtils.kt
index 133a709..0d889a4 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/crypto/CryptoUtils.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/CryptoUtils.kt
@@ -1,6 +1,6 @@
//@file:JvmName("CryptoUtils")
-package ballast.crypto
+package rhodium.crypto
import dev.whyoleg.cryptography.algorithms.SHA256
import fr.acinq.secp256k1.Hex
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/net/HttpClient.kt b/rhodium-core/src/commonMain/kotlin/rhodium/net/HttpClient.kt
similarity index 84%
rename from rhodium-core/src/commonMain/kotlin/ballast/net/HttpClient.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/net/HttpClient.kt
index 19324c7..f0235b3 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/net/HttpClient.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/net/HttpClient.kt
@@ -1,4 +1,4 @@
-package ballast.net
+package rhodium.net
import io.ktor.client.*
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/net/NostrService.kt b/rhodium-core/src/commonMain/kotlin/rhodium/net/NostrService.kt
similarity index 96%
rename from rhodium-core/src/commonMain/kotlin/ballast/net/NostrService.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/net/NostrService.kt
index 2ffbfba..744dcc9 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/net/NostrService.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/net/NostrService.kt
@@ -1,14 +1,14 @@
-package ballast.net
-
-import ballast.formattedDateTime
-import ballast.nostr.Event
-import ballast.nostr.client.ClientMessage
-import ballast.nostr.client.RequestMessage
-import ballast.nostr.deserializedEvent
-import ballast.nostr.EventKind
-import ballast.nostr.eventMapper
-import ballast.nostr.NostrFilter
-import ballast.nostr.relay.*
+package rhodium.net
+
+import rhodium.formattedDateTime
+import rhodium.nostr.Event
+import rhodium.nostr.client.ClientMessage
+import rhodium.nostr.client.RequestMessage
+import rhodium.nostr.deserializedEvent
+import rhodium.nostr.EventKind
+import rhodium.nostr.eventMapper
+import rhodium.nostr.NostrFilter
+import rhodium.nostr.relay.*
import io.ktor.client.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt b/rhodium-core/src/commonMain/kotlin/rhodium/net/NostrUtils.kt
similarity index 95%
rename from rhodium-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/net/NostrUtils.kt
index 2a394c4..2ad18a6 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/net/NostrUtils.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/net/NostrUtils.kt
@@ -1,8 +1,8 @@
-package ballast.net
+package rhodium.net
-import ballast.nostr.Nip05ValidationError
-import ballast.nostr.arraySerializer
-import ballast.nostr.eventMapper
+import rhodium.nostr.Nip05ValidationError
+import rhodium.nostr.arraySerializer
+import rhodium.nostr.eventMapper
import io.ktor.client.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt b/rhodium-core/src/commonMain/kotlin/rhodium/net/UrlUtil.kt
similarity index 99%
rename from rhodium-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/net/UrlUtil.kt
index 226f3d4..2077025 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/net/UrlUtil.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/net/UrlUtil.kt
@@ -2,7 +2,7 @@
* The source code below originates from https://github.com/chRyNaN/validator.
* Credits : chRyNaN, Android URLUtil class devs.
*/
-package ballast.net
+package rhodium.net
object UrlUtil {
private val URL_REGEX = Regex(WebRegexConstants.WEB_URL)
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/Event.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/Event.kt
similarity index 95%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/Event.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/Event.kt
index 0c41c00..2244ecd 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/Event.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/Event.kt
@@ -1,13 +1,13 @@
-package ballast.nostr
+package rhodium.nostr
+import rhodium.crypto.CryptoUtils
+import rhodium.crypto.toHexString
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonArray
-import ballast.crypto.CryptoUtils
-import ballast.crypto.toHexString
/**
* The Event class representing the Nostr Event.
@@ -138,10 +138,16 @@ enum class EventKind(val kind: Int) {
*/
MARKED_FOR_DELETION(5),
+ /**
+ * Represents a profile's relay list.
+ */
+ RELAY_LIST(10002),
+
/**
* This is used for auth events constructed by the client.
*/
AUTH(22242),
+
/**
* This is used for comments on any posts other than Kind 1 posts(i.e, blogposts, shared file events,etc).
*/
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/EventExt.kt
similarity index 98%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/EventExt.kt
index 4d74796..d0e57d3 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/EventExt.kt
@@ -1,4 +1,4 @@
-package ballast.nostr
+package rhodium.nostr
import fr.acinq.secp256k1.Hex
import kotlinx.serialization.ExperimentalSerializationApi
@@ -10,7 +10,7 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
-import ballast.crypto.CryptoUtils
+import rhodium.crypto.CryptoUtils
internal val eventMapper = Json
@OptIn(ExperimentalSerializationApi::class)
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/Events.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/Events.kt
similarity index 96%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/Events.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/Events.kt
index cc56595..452fa07 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/Events.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/Events.kt
@@ -1,11 +1,11 @@
@file:JvmName("EventUtils")
-package ballast.nostr
+package rhodium.nostr
import fr.acinq.secp256k1.Secp256k1
-import ballast.crypto.CryptoUtils
-import ballast.crypto.toBytes
-import ballast.crypto.toHexString
-import ballast.currentSystemTimestamp
+import rhodium.crypto.CryptoUtils
+import rhodium.crypto.toBytes
+import rhodium.crypto.toHexString
+import rhodium.currentSystemTimestamp
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/NostrErrors.kt
similarity index 98%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/NostrErrors.kt
index 14263f6..aebdf51 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrErrors.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/NostrErrors.kt
@@ -1,4 +1,4 @@
-package ballast.nostr
+package rhodium.nostr
//The general class of Nostr Errors.
sealed class NostrException : RuntimeException {
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/NostrFilter.kt
similarity index 99%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/NostrFilter.kt
index ee58925..039c2d5 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/NostrFilter.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/NostrFilter.kt
@@ -1,4 +1,4 @@
-package ballast.nostr
+package rhodium.nostr
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/Tag.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/Tag.kt
similarity index 99%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/Tag.kt
index 50e9f72..688f2c5 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/Tag.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/Tag.kt
@@ -1,5 +1,5 @@
//@file:JvmName("Tag")
-package ballast.nostr
+package rhodium.nostr
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/client/ClientMessage.kt
similarity index 98%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/client/ClientMessage.kt
index d5976f1..27a4913 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/client/ClientMessage.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/client/ClientMessage.kt
@@ -1,8 +1,5 @@
-package ballast.nostr.client
+package rhodium.nostr.client
-import ballast.crypto.toHexString
-import ballast.nostr.Event
-import ballast.nostr.NostrFilter
import com.benasher44.uuid.bytes
import com.benasher44.uuid.uuid4
import kotlinx.serialization.ExperimentalSerializationApi
@@ -15,6 +12,9 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.*
+import rhodium.crypto.toHexString
+import rhodium.nostr.Event
+import rhodium.nostr.NostrFilter
@Serializable(with = ClientMessage.MessageSerializer::class)
sealed class ClientMessage(open val messageType: String){
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/Relay.kt
similarity index 89%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/Relay.kt
index a83097c..676e3c4 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/Relay.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/Relay.kt
@@ -1,4 +1,4 @@
-package ballast.nostr.relay
+package rhodium.nostr.relay
class Relay(
val relayURI: String,
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/RelayMessage.kt
similarity index 99%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/RelayMessage.kt
index 5aac261..f65bd51 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayMessage.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/RelayMessage.kt
@@ -1,6 +1,6 @@
-package ballast.nostr.relay
+package rhodium.nostr.relay
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
@@ -177,7 +177,7 @@ sealed class RelayMessage(){
* Typically, the data is a JSON array of 3 elements, which look like this: [[EVENT, subscriptionId, eventJson]].
* Though the eventJson returned here is in a String format, it will need to be parsed for a client to make
* sense of it. You can do so using the provided deserializedEvent() function.
- * @see ballast.nostr.deserializedEvent
+ * @see rhodium.nostr.deserializedEvent
*/
@Serializable
diff --git a/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/RelayPool.kt
similarity index 96%
rename from rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
rename to rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/RelayPool.kt
index 1c722d6..95232b4 100644
--- a/rhodium-core/src/commonMain/kotlin/ballast/nostr/relay/RelayPool.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/nostr/relay/RelayPool.kt
@@ -1,6 +1,6 @@
-package ballast.nostr.relay
+package rhodium.nostr.relay
-import ballast.nostr.RelayError
+import rhodium.nostr.RelayError
import kotlin.jvm.JvmStatic
class RelayPool {
diff --git a/rhodium-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt b/rhodium-core/src/commonTest/kotlin/rhodium/crypto/CryptoUtilsTest.kt
similarity index 98%
rename from rhodium-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt
rename to rhodium-core/src/commonTest/kotlin/rhodium/crypto/CryptoUtilsTest.kt
index f78cacd..61e1fc1 100644
--- a/rhodium-core/src/commonTest/kotlin/ballast/crypto/CryptoUtilsTest.kt
+++ b/rhodium-core/src/commonTest/kotlin/rhodium/crypto/CryptoUtilsTest.kt
@@ -1,4 +1,4 @@
-package ballast.crypto
+package rhodium.crypto
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/rhodium-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/EventTests.kt
similarity index 99%
rename from rhodium-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt
rename to rhodium-core/src/commonTest/kotlin/rhodium/nostr/EventTests.kt
index a3544b3..82c5a1e 100644
--- a/rhodium-core/src/commonTest/kotlin/ballast/nostr/EventTests.kt
+++ b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/EventTests.kt
@@ -1,4 +1,4 @@
-package ballast.nostr
+package rhodium.nostr
import kotlinx.serialization.json.Json
import kotlin.test.Test
diff --git a/rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/NostrFilterTest.kt
similarity index 98%
rename from rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt
rename to rhodium-core/src/commonTest/kotlin/rhodium/nostr/NostrFilterTest.kt
index fa790ca..41a7719 100644
--- a/rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrFilterTest.kt
+++ b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/NostrFilterTest.kt
@@ -1,8 +1,8 @@
-package ballast.nostr
+package rhodium.nostr
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
-import ballast.currentSystemTimestamp
+import rhodium.currentSystemTimestamp
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/NostrTests.kt
similarity index 99%
rename from rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt
rename to rhodium-core/src/commonTest/kotlin/rhodium/nostr/NostrTests.kt
index ac8d1f9..51cd22d 100644
--- a/rhodium-core/src/commonTest/kotlin/ballast/nostr/NostrTests.kt
+++ b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/NostrTests.kt
@@ -1,4 +1,4 @@
-package ballast.nostr
+package rhodium.nostr
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/rhodium-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/client/ClientMessageTests.kt
similarity index 98%
rename from rhodium-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt
rename to rhodium-core/src/commonTest/kotlin/rhodium/nostr/client/ClientMessageTests.kt
index 02a9983..024b370 100644
--- a/rhodium-core/src/commonTest/kotlin/ballast/nostr/client/ClientMessageTests.kt
+++ b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/client/ClientMessageTests.kt
@@ -1,9 +1,9 @@
-package ballast.nostr.client
+package rhodium.nostr.client
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
-import ballast.nostr.EventKind
-import ballast.nostr.NostrFilter
+import rhodium.nostr.EventKind
+import rhodium.nostr.NostrFilter
import kotlin.jvm.JvmStatic
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/rhodium-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/relay/RelayMessageTests.kt
similarity index 98%
rename from rhodium-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt
rename to rhodium-core/src/commonTest/kotlin/rhodium/nostr/relay/RelayMessageTests.kt
index 4813ac3..25579ce 100644
--- a/rhodium-core/src/commonTest/kotlin/ballast/nostr/relay/RelayMessageTests.kt
+++ b/rhodium-core/src/commonTest/kotlin/rhodium/nostr/relay/RelayMessageTests.kt
@@ -1,4 +1,4 @@
-package ballast.nostr.relay
+package rhodium.nostr.relay
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
diff --git a/rhodium-core/src/linuxMain/kotlin/Entry.kt b/rhodium-core/src/linuxMain/kotlin/Entry.kt
index 753f677..9d97272 100644
--- a/rhodium-core/src/linuxMain/kotlin/Entry.kt
+++ b/rhodium-core/src/linuxMain/kotlin/Entry.kt
@@ -1,5 +1,5 @@
import kotlinx.coroutines.runBlocking
fun main() = runBlocking {
- ballast.main()
+ rhodium.main()
}
\ No newline at end of file
diff --git a/rhodium-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt b/rhodium-core/src/linuxMain/kotlin/rhodium/crypto/CryptoProvider.linux.kt
similarity index 93%
rename from rhodium-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt
rename to rhodium-core/src/linuxMain/kotlin/rhodium/crypto/CryptoProvider.linux.kt
index 470c0f3..f4b474a 100644
--- a/rhodium-core/src/linuxMain/kotlin/ballast/crypto/CryptoProvider.linux.kt
+++ b/rhodium-core/src/linuxMain/kotlin/rhodium/crypto/CryptoProvider.linux.kt
@@ -1,4 +1,4 @@
-package ballast.crypto
+package rhodium.crypto
import dev.whyoleg.cryptography.CryptographyProvider
import dev.whyoleg.cryptography.providers.openssl3.Openssl3
diff --git a/rhodium-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt b/rhodium-core/src/linuxMain/kotlin/rhodium/net/HttpClient.linux.kt
similarity index 90%
rename from rhodium-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt
rename to rhodium-core/src/linuxMain/kotlin/rhodium/net/HttpClient.linux.kt
index f53bb21..30e9865 100644
--- a/rhodium-core/src/linuxMain/kotlin/ballast/net/HttpClient.linux.kt
+++ b/rhodium-core/src/linuxMain/kotlin/rhodium/net/HttpClient.linux.kt
@@ -1,4 +1,4 @@
-package ballast.net
+package rhodium.net
import io.ktor.client.*
import io.ktor.client.engine.cio.*
From 9e87a9937edddbd8202fc153100593d79c17e07e Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 09:55:13 +0100
Subject: [PATCH 31/35] Remove the file that should not have been.
---
rhodium-core/src/linuxMain/kotlin/Entry.kt | 5 -----
1 file changed, 5 deletions(-)
delete mode 100644 rhodium-core/src/linuxMain/kotlin/Entry.kt
diff --git a/rhodium-core/src/linuxMain/kotlin/Entry.kt b/rhodium-core/src/linuxMain/kotlin/Entry.kt
deleted file mode 100644
index 9d97272..0000000
--- a/rhodium-core/src/linuxMain/kotlin/Entry.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-import kotlinx.coroutines.runBlocking
-
-fun main() = runBlocking {
- rhodium.main()
-}
\ No newline at end of file
From 9b366ef7d3252b37abcd9e8be017b60dcbba86d7 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 10:07:35 +0100
Subject: [PATCH 32/35] Re-enable build on push.
---
.github/workflows/publish.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 2f5d535..5476b84 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,8 +1,8 @@
name: Publish
on:
-# push:
-# branches: ["develop"]
+ push:
+ branches: ["develop"]
release:
types: [released]
From 8a8f1d245df3469d9ce5602d9abe57295c6c9ceb Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 19:31:45 +0100
Subject: [PATCH 33/35] Bech32 support(encode/decode, parsing). Adapt copied
code to KMP.
---
rhodium-core/build.gradle.kts | 2 +
.../kotlin/rhodium/crypto/Bech32Util.kt | 308 ++++++++++++++++++
.../kotlin/rhodium/crypto/Identity.kt | 37 +++
.../kotlin/rhodium/crypto/Nip19Parser.kt | 220 +++++++++++++
.../kotlin/rhodium/crypto/tlv/Tlv.kt | 96 ++++++
.../kotlin/rhodium/crypto/tlv/TlvBuilder.kt | 99 ++++++
.../kotlin/rhodium/crypto/tlv/TlvTypes.kt | 63 ++++
.../rhodium/crypto/tlv/entity/Entity.kt | 47 +++
.../rhodium/crypto/tlv/entity/EntityUtils.kt | 65 ++++
.../rhodium/crypto/tlv/entity/NAddress.kt | 105 ++++++
.../rhodium/crypto/tlv/entity/NEvent.kt | 88 +++++
.../rhodium/crypto/tlv/entity/NProfile.kt | 82 +++++
.../kotlin/rhodium/crypto/tlv/entity/NPub.kt | 61 ++++
.../rhodium/crypto/tlv/entity/NRelay.kt | 62 ++++
.../kotlin/rhodium/crypto/tlv/entity/NSec.kt | 58 ++++
.../kotlin/rhodium/crypto/tlv/entity/Note.kt | 61 ++++
16 files changed, 1454 insertions(+)
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/Bech32Util.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/Identity.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/Nip19Parser.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/Tlv.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/TlvBuilder.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/TlvTypes.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/Entity.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/EntityUtils.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NAddress.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NEvent.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NProfile.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NPub.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NRelay.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NSec.kt
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/Note.kt
diff --git a/rhodium-core/build.gradle.kts b/rhodium-core/build.gradle.kts
index d299d38..b36f9c5 100644
--- a/rhodium-core/build.gradle.kts
+++ b/rhodium-core/build.gradle.kts
@@ -107,6 +107,8 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
//UUID
implementation("com.benasher44:uuid:0.8.4")
+ //ByteBuffer(until a kotlinx-io replacement appears)
+ implementation("com.ditchoom:buffer:1.4.2")
}
commonTest.dependencies {
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Bech32Util.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Bech32Util.kt
new file mode 100644
index 0000000..b638bd8
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Bech32Util.kt
@@ -0,0 +1,308 @@
+/**
+ * Copyright (c) 2022 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.crypto
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////////
+/*
+ * Copyright 2020 ACINQ SAS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import kotlin.jvm.JvmStatic
+/**
+ * Bech32 works with 5 bits values, we use this type to make it explicit: whenever you see Int5 it
+ * means 5 bits values, and whenever you see Byte it means 8 bits values.
+ */
+private typealias Int5 = Byte
+
+/**
+ * Bech32 and Bech32m address formats. See
+ * https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki and
+ * https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki.
+ */
+object Bech32 {
+ const val ALPHABET: String = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
+ const val ALPHABET_UPPERCASE: String = "QPZRY9X8GF2TVDW0S3JN54KHCE6MUA7L"
+
+ enum class Encoding(
+ val constant: Int,
+ ) {
+ Bech32(1),
+ Bech32m(0x2bc830a3),
+ Beck32WithoutChecksum(0),
+ }
+
+ // char -> 5 bits value
+ private val map = Array(255) { -1 }
+
+ init {
+ for (i in 0..ALPHABET.lastIndex) {
+ map[ALPHABET[i].code] = i.toByte()
+ }
+ for (i in 0..ALPHABET_UPPERCASE.lastIndex) {
+ map[ALPHABET_UPPERCASE[i].code] = i.toByte()
+ }
+ }
+
+ fun expand(hrp: String): Array {
+ val half = hrp.length + 1
+ val size = half + hrp.length
+ return Array(size) {
+ when (it) {
+ in hrp.indices -> hrp[it].code.shr(5).toByte()
+ in half until size -> (hrp[it - half].code and 31).toByte()
+ else -> 0
+ }
+ }
+ }
+
+ private val GEN = arrayOf(0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3)
+
+ fun polymod(
+ values: Array,
+ values1: Array,
+ ): Int {
+ var chk = 1
+ values.forEach { v ->
+ val b = chk shr 25
+ chk = ((chk and 0x1ffffff) shl 5) xor v.toInt()
+ for (i in 0..4) {
+ if (((b shr i) and 1) != 0) chk = chk xor GEN[i]
+ }
+ }
+ values1.forEach { v ->
+ val b = chk shr 25
+ chk = ((chk and 0x1ffffff) shl 5) xor v.toInt()
+ for (i in 0..4) {
+ if (((b shr i) and 1) != 0) chk = chk xor GEN[i]
+ }
+ }
+ return chk
+ }
+
+ /**
+ * @param hrp human readable prefix
+ * @param int5s 5-bit data
+ * @param encoding encoding to use (bech32 or bech32m)
+ * @return hrp + data encoded as a Bech32 string
+ */
+ @JvmStatic
+ public fun encode(
+ hrp: String,
+ int5s: ArrayList,
+ encoding: Encoding,
+ ): String {
+ require(hrp.lowercase() == hrp || hrp.uppercase() == hrp) {
+ "mixed case strings are not valid bech32 prefixes"
+ }
+ val dataWithChecksum =
+ when (encoding) {
+ Encoding.Beck32WithoutChecksum -> int5s
+ else -> addChecksum(hrp, int5s, encoding)
+ }
+
+ val charArray =
+ CharArray(dataWithChecksum.size) { ALPHABET[dataWithChecksum[it].toInt()] }.concatToString()
+
+ return hrp + "1" + charArray
+ }
+
+ /**
+ * @param hrp human readable prefix
+ * @param data data to encode
+ * @param encoding encoding to use (bech32 or bech32m)
+ * @return hrp + data encoded as a Bech32 string
+ */
+ @JvmStatic
+ public fun encodeBytes(
+ hrp: String,
+ data: ByteArray,
+ encoding: Encoding,
+ ): String = encode(hrp, eight2five(data), encoding)
+
+ /**
+ * decodes a bech32 string
+ *
+ * @param bech32 bech32 string
+ * @param noChecksum if true, the bech32 string doesn't have a checksum
+ * @return a (hrp, data, encoding) tuple
+ */
+ @JvmStatic
+ public fun decode(
+ bech32: String,
+ noChecksum: Boolean = false,
+ ): Triple, Encoding> {
+ var pos = 0
+ bech32.forEachIndexed { index, char ->
+ require(char.code in 33..126) { "invalid character $char" }
+ if (char == '1') {
+ pos = index
+ }
+ }
+
+ val hrp = bech32.take(pos).lowercase() // strings must be lower case
+ require(hrp.length in 1..83) { "hrp must contain 1 to 83 characters" }
+
+ val data = Array(bech32.length - pos - 1) { map[bech32[pos + 1 + it].code] }
+
+ return if (noChecksum) {
+ Triple(hrp, data, Encoding.Beck32WithoutChecksum)
+ } else {
+ val encoding =
+ when (polymod(expand(hrp), data)) {
+ Encoding.Bech32.constant -> Encoding.Bech32
+ Encoding.Bech32m.constant -> Encoding.Bech32m
+ else -> throw IllegalArgumentException("invalid checksum for $bech32")
+ }
+ Triple(hrp, data.copyOfRange(0, data.size - 6), encoding)
+ }
+ }
+
+ /**
+ * decodes a bech32 string
+ *
+ * @param bech32 bech32 string
+ * @param noChecksum if true, the bech32 string doesn't have a checksum
+ * @return a (hrp, data, encoding) tuple
+ */
+ @JvmStatic
+ public fun decodeBytes(
+ bech32: String,
+ noChecksum: Boolean = false,
+ ): Triple {
+ val (hrp, int5s, encoding) = decode(bech32, noChecksum)
+ return Triple(hrp, five2eight(int5s, 0), encoding)
+ }
+
+ val ZEROS = arrayOf(0.toByte(), 0.toByte(), 0.toByte(), 0.toByte(), 0.toByte(), 0.toByte())
+
+ /**
+ * @param hrp Human Readable Part
+ * @param data data (a sequence of 5 bits integers)
+ * @param encoding encoding to use (bech32 or bech32m)
+ * @return a checksum computed over hrp and data
+ */
+ private fun addChecksum(
+ hrp: String,
+ data: ArrayList,
+ encoding: Encoding,
+ ): ArrayList {
+ val values = expand(hrp) + data
+ val poly = polymod(values, ZEROS) xor encoding.constant
+
+ for (i in 0 until 6) {
+ data.add((poly.shr(5 * (5 - i)) and 31).toByte())
+ }
+
+ return data
+ }
+
+ /**
+ * @param input a sequence of 8 bits integers
+ * @return a sequence of 5 bits integers
+ */
+ @JvmStatic
+ public fun eight2five(input: ByteArray): ArrayList {
+ var buffer = 0L
+ val output =
+ ArrayList(input.size * 2) // larger array on purpose. Checksum is added later.
+ var count = 0
+ input.forEach { b ->
+ buffer = (buffer shl 8) or (b.toLong() and 0xff)
+ count += 8
+ while (count >= 5) {
+ output.add(((buffer shr (count - 5)) and 31).toByte())
+ count -= 5
+ }
+ }
+ if (count > 0) output.add(((buffer shl (5 - count)) and 31).toByte())
+ return output
+ }
+
+ /**
+ * @param input a sequence of 5 bits integers
+ * @return a sequence of 8 bits integers
+ */
+ @JvmStatic
+ public fun five2eight(
+ input: Array,
+ offset: Int,
+ ): ByteArray {
+ var buffer = 0L
+ val output = ArrayList(input.size)
+ var count = 0
+ for (i in offset..input.lastIndex) {
+ val b = input[i]
+ buffer = (buffer shl 5) or (b.toLong() and 31)
+ count += 5
+ while (count >= 8) {
+ output.add(((buffer shr (count - 8)) and 0xff).toByte())
+ count -= 8
+ }
+ }
+ require(count <= 4) { "Zero-padding of more than 4 bits" }
+ require((buffer and ((1L shl count) - 1L)) == 0L) { "Non-zero padding in 8-to-5 conversion" }
+ return output.toByteArray()
+ }
+}
+
+fun String.bechToBytes(hrp: String? = null): ByteArray {
+ val decodedForm = Bech32.decodeBytes(this)
+ hrp?.also {
+ if (it != decodedForm.first) {
+ throw IllegalArgumentException("Expected $it but obtained ${decodedForm.first}")
+ }
+ }
+ return decodedForm.second
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Identity.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Identity.kt
new file mode 100644
index 0000000..e28563f
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Identity.kt
@@ -0,0 +1,37 @@
+/**
+ * This file is copied(and modified) from https://github.com/Giszmo/NostrPostr.
+ * Credits: Giszmo(on Github)
+ */
+
+package rhodium.crypto
+
+class Identity(
+ privKey: ByteArray? = null,
+ pubKey: ByteArray? = null
+) {
+ val privKey: ByteArray?
+ val pubKey: ByteArray
+
+ init {
+ if (privKey == null) {
+ if (pubKey == null) {
+ // create new, random keys
+ this.privKey = CryptoUtils.generatePrivateKey()
+ this.pubKey = CryptoUtils.getPublicKey(this.privKey)
+ } else {
+ // this is a read-only account
+ check(pubKey.size == 32)
+ this.privKey = null
+ this.pubKey = pubKey
+ }
+ } else {
+ // as private key is provided, ignore the public key and set keys according to private key
+ this.privKey = privKey
+ this.pubKey = CryptoUtils.getPublicKey(privKey)
+ }
+ }
+
+ override fun toString(): String {
+ return "Persona(privateKey=${privKey?.toHexString()}, publicKey=${pubKey.toHexString()})"
+ }
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Nip19Parser.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Nip19Parser.kt
new file mode 100644
index 0000000..ff652c8
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Nip19Parser.kt
@@ -0,0 +1,220 @@
+/**
+ * Copyright (c) 2022 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.crypto
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import fr.acinq.secp256k1.Hex
+import kotlinx.coroutines.CancellationException
+import rhodium.crypto.tlv.entity.*
+
+object Nip19Parser {
+ private val nip19PlusNip46regex: Regex =
+ Regex(
+ "(nostr:)?@?(nsec1|npub1|nevent1|naddr1|note1|nprofile1|nrelay1|nembed1|ncryptsec1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)([\\S]*)",
+ RegexOption.IGNORE_CASE,
+ )
+
+ val nip19regex: Regex =
+ Regex(
+ "(nostr:)?@?(nsec1|npub1|nevent1|naddr1|note1|nprofile1|nrelay1|nembed1)([qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)([\\S]*)",
+ RegexOption.IGNORE_CASE,
+ )
+
+ data class ParseReturn(
+ val entity: Entity,
+ val nip19raw: String,
+ val additionalChars: String? = null,
+ )
+
+ fun tryParseAndClean(uri: String?): String? {
+ if (uri == null) return null
+
+ try {
+ val matcher = nip19PlusNip46regex.find(uri)
+ if (matcher == null) {
+ return null
+ }
+
+ val type = matcher.groups[2]?.value // npub1
+ val key = matcher.groups[3]?.value // bech32
+
+ return type + key
+ } catch (e: Throwable) {
+ println("NIP19 Parser: Issue trying to Decode NIP19 $uri: ${e.message}")
+ }
+
+ return null
+ }
+
+ fun uriToRoute(uri: String?): ParseReturn? {
+ if (uri == null) return null
+
+ try {
+ val matcher = nip19regex.find(uri)
+ if (matcher == null) {
+ return null
+ }
+
+ val type = matcher.groups[2]?.value // npub1
+ val key = matcher.groups[3]?.value // bech32
+ val additionalChars = matcher.groups[4]?.value // additional chars
+
+ if (type == null) return null
+
+ return parseComponents(type, key, additionalChars?.ifEmpty { null })
+ } catch (e: Throwable) {
+ println("NIP19 Parser: Issue trying to Decode NIP19 $uri: ${e.message}")
+ }
+
+ return null
+ }
+
+ fun parseComponents(
+ type: String,
+ key: String?,
+ additionalChars: String?,
+ ): ParseReturn? =
+ try {
+ val nip19 = (type + key)
+ val bytes = nip19.bechToBytes()
+
+ when (type.lowercase()) {
+ "nsec1" -> NSec.parse(bytes)
+ "npub1" -> NPub.parse(bytes)
+ "note1" -> Note.parse(bytes)
+ "nprofile1" -> NProfile.parse(bytes)
+ "nevent1" -> NEvent.parse(bytes)
+ "nrelay1" -> NRelay.parse(bytes)
+ "naddr1" -> NAddress.parse(bytes)
+// "nembed1" -> NEmbed.parse(bytes)
+ else -> null
+ }?.let {
+ ParseReturn(it, nip19, additionalChars)
+ }
+ } catch (e: Throwable) {
+ println("NIP19 Parser: Issue trying to Decode NIP19 $key: ${e.message}")
+ null
+ }
+
+ fun parseAll(content: String): List {
+ val matcher2 = nip19regex.findAll(content)
+ val returningList = mutableListOf()
+ matcher2.forEach { result ->
+ val type = result.groups[2]?.value // npub1
+ val key = result.groups[3]?.value // bech32
+ val additionalChars = result.groups[4]?.value // additional chars
+
+ if (type != null) {
+ val parsed = Nip19Parser.parseComponents(type, key, additionalChars)?.entity
+
+ if (parsed != null) {
+ returningList.add(parsed)
+ }
+ }
+ }
+ return returningList
+ }
+}
+
+fun decodePublicKey(key: String): ByteArray =
+ when (val parsed = Nip19Parser.uriToRoute(key)?.entity) {
+ is NSec -> Identity(privKey = key.bechToBytes()).pubKey
+ is NPub -> parsed.hex.toBytes()
+ is NProfile -> parsed.hex.toBytes()
+ else -> Hex.decode(key) // crashes on purpose
+ }
+
+fun decodePrivateKeyAsHexOrNull(key: String): String? =
+ try {
+ when (val parsed = Nip19Parser.uriToRoute(key)?.entity) {
+ is NSec -> parsed.hex
+ is NPub -> null
+ is NProfile -> null
+ is Note -> null
+ is NEvent -> null
+// is NEmbed -> null
+ is NRelay -> null
+ is NAddress -> null
+ else -> Hex.decode(key).toHexString()
+ }
+ } catch (e: Exception) {
+ if (e is CancellationException) throw e
+ null
+ }
+
+fun decodePublicKeyAsHexOrNull(key: String): String? =
+ try {
+ when (val parsed = Nip19Parser.uriToRoute(key)?.entity) {
+ is NSec -> Identity(privKey = key.bechToBytes()).pubKey.toHexString()
+ is NPub -> parsed.hex
+ is NProfile -> parsed.hex
+ is Note -> null
+ is NEvent -> null
+// is NEmbed -> null
+ is NRelay -> null
+ is NAddress -> null
+ else -> Hex.decode(key).toHexString()
+ }
+ } catch (e: Exception) {
+ if (e is CancellationException) throw e
+ null
+ }
+
+fun decodeEventIdAsHexOrNull(key: String): String? =
+ try {
+ when (val parsed = Nip19Parser.uriToRoute(key)?.entity) {
+ is NSec -> null
+ is NPub -> null
+ is NProfile -> null
+ is Note -> parsed.hex
+ is NEvent -> parsed.hex
+ is NAddress -> parsed.aTag()
+// is NEmbed -> null
+ is NRelay -> null
+ else -> Hex.decode(key).toHexString()
+ }
+ } catch (e: Exception) {
+ if (e is CancellationException) throw e
+ null
+ }
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/Tlv.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/Tlv.kt
new file mode 100644
index 0000000..ecb30c2
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/Tlv.kt
@@ -0,0 +1,96 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import com.ditchoom.buffer.ByteOrder
+import com.ditchoom.buffer.PlatformBuffer
+import com.ditchoom.buffer.wrap
+import kotlinx.io.bytestring.ByteString
+import kotlinx.io.bytestring.decodeToString
+import rhodium.crypto.toHexString
+
+class Tlv(
+ val data: Map>,
+) {
+ fun asInt(type: Byte) = data[type]?.mapNotNull { it.toInt32() }
+
+ fun asHex(type: Byte) = data[type]?.map { it.toHexString() }
+
+ fun asString(type: Byte) = data[type]?.map { ByteString(it).decodeToString() }
+
+ fun firstAsInt(type: Byte) = data[type]?.firstOrNull()?.toInt32()
+
+ fun firstAsHex(type: Byte) = data[type]?.firstOrNull()?.toHexString()
+
+ fun firstAsString(type: Byte) = data[type]?.firstOrNull()?.run { ByteString(this).decodeToString() }
+
+ fun asStringList(type: Byte) = data[type]?.map { ByteString(it).decodeToString() }
+
+ companion object {
+ fun parse(data: ByteArray): Tlv {
+ val result = mutableMapOf>()
+ var rest = data
+ while (rest.isNotEmpty()) {
+ val t = rest[0]
+ val l = rest[1].toUByte().toInt()
+ val v = rest.sliceArray(IntRange(2, (2 + l) - 1))
+ rest = rest.sliceArray(IntRange(2 + l, rest.size - 1))
+ if (v.size < l) continue
+
+ if (!result.containsKey(t)) {
+ result[t] = mutableListOf()
+ }
+ result[t]?.add(v)
+ }
+ return Tlv(result)
+ }
+ }
+}
+
+fun ByteArray.toInt32(): Int? {
+ if (size != 4) return null
+
+ return PlatformBuffer.wrap(this.copyOfRange(0, 4), ByteOrder.BIG_ENDIAN).readInt()
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/TlvBuilder.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/TlvBuilder.kt
new file mode 100644
index 0000000..683b5c1
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/TlvBuilder.kt
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import kotlinx.io.Buffer
+import kotlinx.io.readByteArray
+import rhodium.crypto.toBytes
+
+class TlvBuilder {
+ val outputStream = Buffer()
+
+ private fun add(
+ type: Byte,
+ byteArray: ByteArray,
+ ) {
+ outputStream.write(byteArrayOf(type, byteArray.size.toByte()))
+ outputStream.write(byteArray)
+ }
+
+ fun addString(
+ type: Byte,
+ string: String,
+ ) = add(type, string.encodeToByteArray())
+
+ fun addHex(
+ type: Byte,
+ key: String,
+ ) = add(type, key.toBytes())
+
+ fun addInt(
+ type: Byte,
+ data: Int,
+ ) = add(type, data.to32BitByteArray())
+
+ fun addStringIfNotNull(
+ type: Byte,
+ data: String?,
+ ) = data?.let { addString(type, it) }
+
+ fun addHexIfNotNull(
+ type: Byte,
+ data: String?,
+ ) = data?.let { addHex(type, it) }
+
+ fun addIntIfNotNull(
+ type: Byte,
+ data: Int?,
+ ) = data?.let { addInt(type, it) }
+
+ fun build(): ByteArray = outputStream.readByteArray()
+}
+
+fun Int.to32BitByteArray(): ByteArray {
+ val bytes = ByteArray(4)
+ (0..3).forEach { bytes[3 - it] = ((this ushr (8 * it)) and 0xFFFF).toByte() }
+ return bytes
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/TlvTypes.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/TlvTypes.kt
new file mode 100644
index 0000000..d12fcde
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/TlvTypes.kt
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+
+enum class TlvTypes(
+ val id: Byte,
+) {
+ SPECIAL(0),
+ RELAY(1),
+ AUTHOR(2),
+ KIND(3),
+}
+
+fun Tlv.firstAsInt(type: TlvTypes) = firstAsInt(type.id)
+
+fun Tlv.firstAsHex(type: TlvTypes) = firstAsHex(type.id)
+
+fun Tlv.firstAsString(type: TlvTypes) = firstAsString(type.id)
+
+fun Tlv.asStringList(type: TlvTypes) = asStringList(type.id)
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/Entity.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/Entity.kt
new file mode 100644
index 0000000..eda1d80
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/Entity.kt
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+interface Entity
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/EntityUtils.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/EntityUtils.kt
new file mode 100644
index 0000000..da827a4
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/EntityUtils.kt
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import rhodium.crypto.Bech32
+
+
+fun ByteArray.toNsec() = Bech32.encodeBytes(hrp = "nsec", this, Bech32.Encoding.Bech32)
+
+fun ByteArray.toNpub() = Bech32.encodeBytes(hrp = "npub", this, Bech32.Encoding.Bech32)
+
+@Deprecated("Prefer nevent1 instead")
+fun ByteArray.toNote() = Bech32.encodeBytes(hrp = "note", this, Bech32.Encoding.Bech32)
+
+fun ByteArray.toNEvent() = Bech32.encodeBytes(hrp = "nevent", this, Bech32.Encoding.Bech32)
+
+fun ByteArray.toNProfile() = Bech32.encodeBytes(hrp = "nprofile", this, Bech32.Encoding.Bech32)
+
+fun ByteArray.toNAddress() = Bech32.encodeBytes(hrp = "naddr", this, Bech32.Encoding.Bech32)
+
+fun ByteArray.toLnUrl() = Bech32.encodeBytes(hrp = "lnurl", this, Bech32.Encoding.Bech32)
+
+fun ByteArray.toNEmbed() = Bech32.encodeBytes(hrp = "nembed", this, Bech32.Encoding.Bech32)
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NAddress.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NAddress.kt
new file mode 100644
index 0000000..6f104bd
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NAddress.kt
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import rhodium.crypto.bechToBytes
+import rhodium.crypto.tlv.Tlv
+import rhodium.crypto.tlv.TlvBuilder
+import rhodium.crypto.tlv.TlvTypes
+
+data class NAddress(
+ val kind: Int,
+ val author: String,
+ val dTag: String,
+ val relay: List,
+) : Entity {
+ fun aTag(): String = "$kind:$author:$dTag"
+
+ companion object {
+ fun parse(naddr: String): NAddress? {
+ try {
+ val key = naddr.removePrefix("nostr:")
+
+ if (key.startsWith("naddr")) {
+ return parse(key.bechToBytes())
+ }
+ } catch (e: Throwable) {
+ Log.w("NAddress", "Issue trying to Decode NIP19 $this: ${e.message}")
+ // e.printStackTrace()
+ }
+
+ return null
+ }
+
+ fun parse(bytes: ByteArray): NAddress? {
+
+ if (bytes.isEmpty()) return null
+
+ val tlv = Tlv.parse(bytes)
+
+ val d = tlv.firstAsString(TlvTypes.SPECIAL.id) ?: ""
+ val relay = tlv.asStringList(TlvTypes.RELAY.id) ?: emptyList()
+ val author = tlv.firstAsHex(TlvTypes.AUTHOR.id) ?: return null
+ val kind = tlv.firstAsInt(TlvTypes.KIND.id) ?: return null
+
+ return NAddress(kind, author, d, relay)
+ }
+
+ fun create(
+ kind: Int,
+ pubKeyHex: String,
+ dTag: String,
+ relay: String?,
+ ): String =
+ TlvBuilder()
+ .apply {
+ addString(TlvTypes.SPECIAL.id, dTag)
+ addStringIfNotNull(TlvTypes.RELAY.id, relay)
+ addHex(TlvTypes.AUTHOR.id, pubKeyHex)
+ addInt(TlvTypes.KIND.id, kind)
+ }.build()
+ .toNAddress()
+ }
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NEvent.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NEvent.kt
new file mode 100644
index 0000000..f9273be
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NEvent.kt
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import rhodium.crypto.tlv.Tlv
+import rhodium.crypto.tlv.TlvBuilder
+import rhodium.crypto.tlv.TlvTypes
+
+data class NEvent(
+ val hex: String,
+ val relay: List,
+ val author: String?,
+ val kind: Int?,
+) : Entity {
+ companion object {
+ fun parse(bytes: ByteArray): NEvent? {
+ if (bytes.isEmpty()) return null
+
+ val tlv = Tlv.parse(bytes)
+
+ val hex = tlv.firstAsHex(TlvTypes.SPECIAL.id) ?: return null
+ val relay = tlv.asStringList(TlvTypes.RELAY.id) ?: emptyList()
+ val author = tlv.firstAsHex(TlvTypes.AUTHOR.id)
+ val kind = tlv.firstAsInt(TlvTypes.KIND.id)
+
+ if (hex.isBlank()) return null
+
+ return NEvent(hex, relay, author, kind)
+ }
+
+ fun create(
+ idHex: String,
+ author: String?,
+ kind: Int?,
+ relay: String?,
+ ): String =
+ TlvBuilder()
+ .apply {
+ addHex(TlvTypes.SPECIAL.id, idHex)
+ addStringIfNotNull(TlvTypes.RELAY.id, relay)
+ addHexIfNotNull(TlvTypes.AUTHOR.id, author)
+ addIntIfNotNull(TlvTypes.KIND.id, kind)
+ }.build()
+ .toNEvent()
+ }
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NProfile.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NProfile.kt
new file mode 100644
index 0000000..cbe3931
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NProfile.kt
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import rhodium.crypto.tlv.Tlv
+import rhodium.crypto.tlv.TlvBuilder
+import rhodium.crypto.tlv.TlvTypes
+
+data class NProfile(
+ val hex: String,
+ val relay: List,
+) : Entity {
+ companion object {
+ fun parse(bytes: ByteArray): NProfile? {
+ if (bytes.isEmpty()) return null
+
+ val tlv = Tlv.parse(bytes)
+
+ val hex = tlv.firstAsHex(TlvTypes.SPECIAL.id) ?: return null
+ val relay = tlv.asStringList(TlvTypes.RELAY.id) ?: emptyList()
+
+ if (hex.isBlank()) return null
+
+ return NProfile(hex, relay)
+ }
+
+ fun create(
+ authorPubKeyHex: String,
+ relays: List,
+ ): String =
+ TlvBuilder()
+ .apply {
+ addHex(TlvTypes.SPECIAL.id, authorPubKeyHex)
+ relays.forEach {
+ addStringIfNotNull(TlvTypes.RELAY.id, it)
+ }
+ }.build()
+ .toNProfile()
+ }
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NPub.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NPub.kt
new file mode 100644
index 0000000..c45761f
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NPub.kt
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import rhodium.crypto.toBytes
+import rhodium.crypto.toHexString
+
+data class NPub(
+ val hex: String,
+) : Entity {
+ companion object {
+ fun parse(bytes: ByteArray): NPub? {
+ if (bytes.isEmpty()) return null
+ return NPub(bytes.toHexString())
+ }
+
+ fun create(authorPubKeyHex: String): String = authorPubKeyHex.toBytes().toNpub()
+ }
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NRelay.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NRelay.kt
new file mode 100644
index 0000000..393fe0d
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NRelay.kt
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+import rhodium.crypto.tlv.Tlv
+import rhodium.crypto.tlv.TlvTypes
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+data class NRelay(
+ val relay: List,
+) : Entity {
+ companion object {
+ fun parse(bytes: ByteArray): NRelay? {
+ if (bytes.isEmpty()) return null
+
+ val relayUrl = Tlv.parse(bytes).asStringList(TlvTypes.SPECIAL.id) ?: return null
+
+ return NRelay(relayUrl)
+ }
+ }
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NSec.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NSec.kt
new file mode 100644
index 0000000..79c9b48
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NSec.kt
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import rhodium.crypto.toHexString
+
+data class NSec(
+ val hex: String,
+) : Entity {
+ companion object {
+ fun parse(bytes: ByteArray): NSec? {
+ if (bytes.isEmpty()) return null
+ return NSec(bytes.toHexString())
+ }
+ }
+}
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/Note.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/Note.kt
new file mode 100644
index 0000000..dd2665e
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/Note.kt
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2022 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.crypto.tlv.entity
+
+/**
+ * Copyright (c) 2024 Vitor Pamplona
+ *
+ * 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.
+ */
+
+import rhodium.crypto.toBytes
+import rhodium.crypto.toHexString
+
+data class Note(
+ val hex: String,
+) : Entity {
+ companion object {
+ fun parse(bytes: ByteArray): Note? {
+ if (bytes.isEmpty()) return null
+ return Note(bytes.toHexString())
+ }
+
+ fun create(eventId: String): String = eventId.toBytes().toNote()
+ }
+}
\ No newline at end of file
From 216aac74c30ec2ca4250d6c2308054263d9514f9 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 20:23:16 +0100
Subject: [PATCH 34/35] Add a logging solution. Disable build on push.
---
.github/workflows/publish.yml | 4 +-
.../kotlin/ballast/nostr/EventExt.kt | 4 +-
rhodium-core/build.gradle.kts | 2 +
.../kotlin/rhodium/crypto/Nip19Parser.kt | 9 ++--
.../rhodium/crypto/tlv/entity/NAddress.kt | 3 +-
.../kotlin/rhodium/logging/Logging.kt | 11 ++++
.../kotlin/rhodium/net/NostrService.kt | 51 +++++++++----------
7 files changed, 48 insertions(+), 36 deletions(-)
create mode 100644 rhodium-core/src/commonMain/kotlin/rhodium/logging/Logging.kt
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 5476b84..2f5d535 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,8 +1,8 @@
name: Publish
on:
- push:
- branches: ["develop"]
+# push:
+# branches: ["develop"]
release:
types: [released]
diff --git a/ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt b/ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
index 4d74796..c356fcf 100644
--- a/ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
+++ b/ballast-core/src/commonMain/kotlin/ballast/nostr/EventExt.kt
@@ -77,7 +77,7 @@ fun Event.isValid(): Boolean {
this.tags, this.content
)
if (eventId != this.id) {
- println("The event id is invalid.")
+ serviceLogger.w("The event id is invalid.")
return false
}
val signatureValidity = CryptoUtils.verifyContentSignature(
@@ -86,7 +86,7 @@ fun Event.isValid(): Boolean {
Hex.decode(eventId)
)
if (!signatureValidity) {
- println("The event signature is invalid.\n Please check the pubkey, or content.")
+ serviceLogger.w("The event signature is invalid.\n Please check the pubkey, or content.")
return false
}
return true
diff --git a/rhodium-core/build.gradle.kts b/rhodium-core/build.gradle.kts
index b36f9c5..7841d79 100644
--- a/rhodium-core/build.gradle.kts
+++ b/rhodium-core/build.gradle.kts
@@ -109,6 +109,8 @@ kotlin {
implementation("com.benasher44:uuid:0.8.4")
//ByteBuffer(until a kotlinx-io replacement appears)
implementation("com.ditchoom:buffer:1.4.2")
+ //Logging
+ implementation("co.touchlab:kermit:2.0.5")
}
commonTest.dependencies {
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Nip19Parser.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Nip19Parser.kt
index ff652c8..c70ba3d 100644
--- a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Nip19Parser.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/Nip19Parser.kt
@@ -47,6 +47,7 @@ package rhodium.crypto
import fr.acinq.secp256k1.Hex
import kotlinx.coroutines.CancellationException
import rhodium.crypto.tlv.entity.*
+import rhodium.logging.serviceLogger
object Nip19Parser {
private val nip19PlusNip46regex: Regex =
@@ -81,7 +82,7 @@ object Nip19Parser {
return type + key
} catch (e: Throwable) {
- println("NIP19 Parser: Issue trying to Decode NIP19 $uri: ${e.message}")
+ serviceLogger.e("NIP19 Parser: Issue trying to Decode NIP19 $uri: ${e.message}", e)
}
return null
@@ -104,7 +105,7 @@ object Nip19Parser {
return parseComponents(type, key, additionalChars?.ifEmpty { null })
} catch (e: Throwable) {
- println("NIP19 Parser: Issue trying to Decode NIP19 $uri: ${e.message}")
+ serviceLogger.e("NIP19 Parser: Issue trying to Decode NIP19 $uri: ${e.message}", e)
}
return null
@@ -133,7 +134,7 @@ object Nip19Parser {
ParseReturn(it, nip19, additionalChars)
}
} catch (e: Throwable) {
- println("NIP19 Parser: Issue trying to Decode NIP19 $key: ${e.message}")
+ serviceLogger.e("NIP19 Parser: Issue trying to Decode NIP19 $key: ${e.message}", e)
null
}
@@ -146,7 +147,7 @@ object Nip19Parser {
val additionalChars = result.groups[4]?.value // additional chars
if (type != null) {
- val parsed = Nip19Parser.parseComponents(type, key, additionalChars)?.entity
+ val parsed = parseComponents(type, key, additionalChars)?.entity
if (parsed != null) {
returningList.add(parsed)
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NAddress.kt b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NAddress.kt
index 6f104bd..e4aeb53 100644
--- a/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NAddress.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/crypto/tlv/entity/NAddress.kt
@@ -48,6 +48,7 @@ import rhodium.crypto.bechToBytes
import rhodium.crypto.tlv.Tlv
import rhodium.crypto.tlv.TlvBuilder
import rhodium.crypto.tlv.TlvTypes
+import rhodium.logging.serviceLogger
data class NAddress(
val kind: Int,
@@ -66,7 +67,7 @@ data class NAddress(
return parse(key.bechToBytes())
}
} catch (e: Throwable) {
- Log.w("NAddress", "Issue trying to Decode NIP19 $this: ${e.message}")
+ serviceLogger.w("Issue trying to Decode NIP19 $this: ${e.message}", e)
// e.printStackTrace()
}
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/logging/Logging.kt b/rhodium-core/src/commonMain/kotlin/rhodium/logging/Logging.kt
new file mode 100644
index 0000000..749f245
--- /dev/null
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/logging/Logging.kt
@@ -0,0 +1,11 @@
+package rhodium.logging
+
+import co.touchlab.kermit.DefaultFormatter
+import co.touchlab.kermit.Logger
+import co.touchlab.kermit.loggerConfigInit
+import co.touchlab.kermit.platformLogWriter
+
+val serviceLogger = Logger(
+ config = loggerConfigInit(platformLogWriter(DefaultFormatter)),
+ tag = "RhodiumLogger"
+)
\ No newline at end of file
diff --git a/rhodium-core/src/commonMain/kotlin/rhodium/net/NostrService.kt b/rhodium-core/src/commonMain/kotlin/rhodium/net/NostrService.kt
index 744dcc9..36cb0e4 100644
--- a/rhodium-core/src/commonMain/kotlin/rhodium/net/NostrService.kt
+++ b/rhodium-core/src/commonMain/kotlin/rhodium/net/NostrService.kt
@@ -1,14 +1,5 @@
package rhodium.net
-import rhodium.formattedDateTime
-import rhodium.nostr.Event
-import rhodium.nostr.client.ClientMessage
-import rhodium.nostr.client.RequestMessage
-import rhodium.nostr.deserializedEvent
-import rhodium.nostr.EventKind
-import rhodium.nostr.eventMapper
-import rhodium.nostr.NostrFilter
-import rhodium.nostr.relay.*
import io.ktor.client.*
import io.ktor.client.plugins.websocket.*
import io.ktor.websocket.*
@@ -18,6 +9,12 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.serialization.encodeToString
+import rhodium.formattedDateTime
+import rhodium.logging.serviceLogger
+import rhodium.nostr.*
+import rhodium.nostr.client.ClientMessage
+import rhodium.nostr.client.RequestMessage
+import rhodium.nostr.relay.*
import kotlin.coroutines.CoroutineContext
@@ -107,7 +104,7 @@ class NostrService(
val requestJson = eventMapper.encodeToString(requestMessage)
launch {
- println("Coroutine Scope @ ${relay.relayURI}")
+ serviceLogger.d("Coroutine Scope @ ${relay.relayURI}")
try {
client.webSocket(urlString = relay.relayURI) {
send(requestJson)
@@ -149,57 +146,57 @@ class NostrService(
for (frame in incoming) {
if (frame is Frame.Close) {
- println("Received a close frame with reason: ${frame.readReason()}")
+ serviceLogger.i("Received a close frame with reason: ${frame.readReason()}")
}
else if (frame is Frame.Binary) {
- println("Received binary data : ${frame.readBytes()}")
+ serviceLogger.i("Received binary data : ${frame.readBytes()}")
}
else if (frame is Frame.Text) {
val message = eventMapper.decodeFromString(frame.readText())
when (message) {
is RelayEventMessage -> {
- println("Event message received from ${endpoint.relayURI}")
+ serviceLogger.d("Event message received from ${endpoint.relayURI}")
val event = deserializedEvent(message.eventJson)
- println("Event created on ${formattedDateTime(event.creationDate)}")
- println(event.content)
+ serviceLogger.d("Event created on ${formattedDateTime(event.creationDate)}")
+ serviceLogger.d(event.content)
results.add(event)
}
is CountResponse -> {
- println("Received Count message: $message")
+ serviceLogger.d("Received Count message: $message")
}
is RelayAuthMessage -> {
- println("Received Auth message: $message")
+ serviceLogger.i("Received Auth message: $message")
serviceMutex.withLock {
if (relayAuthCache.put(endpoint, message) != null){
- println("Added auth message <-$message-> to cache.")
+ serviceLogger.i("Added auth message <-$message-> to cache.")
}
}
}
is EventStatus -> {
- println("Received a status for the sent event:")
- println(message)
+ serviceLogger.d("Received a status for the sent event:")
+ serviceLogger.d(message.toString())
}
is RelayEose -> {
relayEoseCount.update { it + 1 }
- println("Relay EOSE received from ${endpoint.relayURI}")
- println(message)
+ serviceLogger.d("Relay EOSE received from ${endpoint.relayURI}")
+ serviceLogger.d(message.toString())
break
}
is CloseMessage -> {
relayEoseCount.update { it + 1 }
- println("Closed by Relay ${endpoint.relayURI} with reason: ${message.errorMessage}")
+ serviceLogger.w("Closed by Relay ${endpoint.relayURI} with reason: ${message.errorMessage}")
this.close()
}
is RelayNotice -> {
- println("Received a relay notice: $message")
+ serviceLogger.i("Received a relay notice: $message")
}
}
@@ -207,7 +204,7 @@ class NostrService(
}
}
} catch (e: Exception) {
- println("Failed to connect to ${endpoint.relayURI}: ${e.message}")
+ serviceLogger.e("Failed to connect to ${endpoint.relayURI}: ${e.message}", e)
relayErrorCount.update { it + 1 }
}
}
@@ -217,8 +214,8 @@ class NostrService(
jobs.forEach { job -> job.join() }
if (jobs.all { it.isCompleted }) {
- println("EoseCount : ${relayEoseCount.value}")
- println("RelayErrorCount: ${relayErrorCount.value}")
+ serviceLogger.d("EoseCount : ${relayEoseCount.value}")
+ serviceLogger.d("RelayErrorCount: ${relayErrorCount.value}")
// if (relayEoseCount.value + relayErrorCount.value == endpoints.size){
// stopService()
//
From 37ebb09cd22b684779fe9db95ef4a3bc50d47084 Mon Sep 17 00:00:00 2001
From: KotlinGeekDev
Date: Fri, 14 Feb 2025 20:42:41 +0100
Subject: [PATCH 35/35] Prepare new release: v1.0-beta-09.
---
README.md | 6 +++---
build.gradle.kts | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 562ad5f..5694ddb 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ You can include the library from either Maven Central or Jitpack.
You can include the library in the common source set like this:
```kotlin
dependencies {
- implementation("io.github.kotlingeekdev:rhodium:1.0-beta-08")
+ implementation("io.github.kotlingeekdev:rhodium:1.0-beta-09")
}
```
@@ -73,7 +73,7 @@ then, in your module's `build.gradle(.kts)`, you need to add:
// build.gradle.kts
dependencies {
//...
- implementation("com.github.KotlinGeekDev.Rhodium:rhodium:1.0-beta-08")
+ implementation("com.github.KotlinGeekDev.Rhodium:rhodium:1.0-beta-09")
}
@@ -83,7 +83,7 @@ If you're including it in an Android app, you can just add:
// app/build.gradle.kts
dependencies {
//...
- implementation("com.github.KotlinGeekDev.Rhodium:rhodium-android:1.0-beta-08")
+ implementation("com.github.KotlinGeekDev.Rhodium:rhodium-android:1.0-beta-09")
}
```
diff --git a/build.gradle.kts b/build.gradle.kts
index 7a9a654..a51d252 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -31,7 +31,7 @@ allprojects {
val isJitpack = System.getenv("JITPACK") == "true"
group = "io.github.kotlingeekdev"
- version = "1.0-beta-08"
+ version = "1.0-beta-09"
// val javadocJar = tasks.register("javadocJar") {