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 [![Kotlin](https://img.shields.io/badge/Kotlin-2.0.20-blue?style=flat&logo=kotlin)](https://kotlinlang.org) +[![Maven Central](https://img.shields.io/maven-central/v/io.github.kotlingeekdev/ballast?color=blue)](https://search.maven.org/search?q=g:io.github.kotlingeekdev) ![badge-jvm](http://img.shields.io/badge/platform-jvm-DB413D.svg?style=flat) ![badge-android](http://img.shields.io/badge/platform-android-6EDB8D.svg?style=flat) 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 [![Kotlin](https://img.shields.io/badge/Kotlin-2.0.20-blue?style=flat&logo=kotlin)](https://kotlinlang.org) [![Maven Central](https://img.shields.io/maven-central/v/io.github.kotlingeekdev/ballast?color=blue)](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") {