From 8189b590d3ec590ccb21fe0863e44c56af5250b4 Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Thu, 28 Mar 2024 19:55:52 -0700 Subject: [PATCH] Implement two way communication with Dero node. - Implemented basic two way communication with the Dero node. The Bridge is listening for Dero node updates and requests the Block Height when receiving a Height update from the node. - Renamed Bridge to StargateBridge and added basic documentation. - Created model for DeroNode instances. We use only one node for now, but will add more down the line. --- .../importaccount/ImportAccountScreenModel.kt | 8 +-- .../net/agorise/shared/stargate/Bridge.kt | 33 ----------- .../net/agorise/shared/stargate/DeroNode.kt | 14 +++++ .../agorise/shared/stargate/StargateBridge.kt | 57 +++++++++++++++++++ 4 files changed, 75 insertions(+), 37 deletions(-) delete mode 100644 shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/Bridge.kt create mode 100644 shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/DeroNode.kt create mode 100644 shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/StargateBridge.kt diff --git a/composeApp/src/commonMain/kotlin/net/agorise/kee/ui/screen/importaccount/ImportAccountScreenModel.kt b/composeApp/src/commonMain/kotlin/net/agorise/kee/ui/screen/importaccount/ImportAccountScreenModel.kt index c9bef82..6a94bf5 100644 --- a/composeApp/src/commonMain/kotlin/net/agorise/kee/ui/screen/importaccount/ImportAccountScreenModel.kt +++ b/composeApp/src/commonMain/kotlin/net/agorise/kee/ui/screen/importaccount/ImportAccountScreenModel.kt @@ -5,19 +5,19 @@ import cafe.adriel.voyager.core.model.screenModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.IO import kotlinx.coroutines.launch -import net.agorise.shared.stargate.Bridge +import net.agorise.shared.stargate.StargateBridge class ImportAccountScreenModel : ScreenModel { - private val bridge = Bridge() + private val stargateBridge = StargateBridge() init { screenModelScope.launch(Dispatchers.IO) { - bridge.start() + stargateBridge.start() } } override fun onDispose() { super.onDispose() - bridge.stop() + stargateBridge.stop() } } diff --git a/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/Bridge.kt b/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/Bridge.kt deleted file mode 100644 index aa7ac3b..0000000 --- a/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/Bridge.kt +++ /dev/null @@ -1,33 +0,0 @@ -package net.agorise.shared.stargate - -import io.ktor.client.HttpClient -import io.ktor.client.engine.cio.CIO -import io.ktor.client.plugins.websocket.DefaultClientWebSocketSession -import io.ktor.client.plugins.websocket.WebSockets -import io.ktor.client.plugins.websocket.webSocket -import io.ktor.http.HttpMethod -import io.ktor.websocket.Frame -import io.ktor.websocket.readText -import kotlinx.coroutines.flow.receiveAsFlow - -class Bridge { - private val client: HttpClient = HttpClient(CIO) { install(WebSockets) } - - suspend fun start() { - client.webSocket(method = HttpMethod.Get, host = "node.derofoundation.org", port = 11012, path = "/ws") { - outputMessages() - } - } - - fun stop() { - client.close() - } - - private suspend fun DefaultClientWebSocketSession.outputMessages() { - incoming.receiveAsFlow().collect { message -> - (message as? Frame.Text)?.let { textFrame -> - println(textFrame.readText()) - } - } - } -} diff --git a/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/DeroNode.kt b/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/DeroNode.kt new file mode 100644 index 0000000..142003f --- /dev/null +++ b/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/DeroNode.kt @@ -0,0 +1,14 @@ +package net.agorise.shared.stargate + +/** + * Represents a Dero node + * + * @param host The host or base url of the node + * @param port The port of the node + * @param path The path of the node + */ +data class DeroNode( + val host: String, + val port: Int, + val path: String, +) diff --git a/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/StargateBridge.kt b/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/StargateBridge.kt new file mode 100644 index 0000000..09d17de --- /dev/null +++ b/shared/stargate/src/commonMain/kotlin/net/agorise/shared/stargate/StargateBridge.kt @@ -0,0 +1,57 @@ +package net.agorise.shared.stargate + +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO +import io.ktor.client.plugins.websocket.DefaultClientWebSocketSession +import io.ktor.client.plugins.websocket.WebSockets +import io.ktor.client.plugins.websocket.webSocket +import io.ktor.websocket.Frame +import io.ktor.websocket.readText +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.receiveAsFlow + +/** + * Bridge to communicate with the DERO Stargate RPC API: https://docs.dero.io/developer/RPC.html + */ +class StargateBridge { + private val foundationNode = DeroNode(host = "node.derofoundation.org", port = 11012, path = "/ws") + + private val client: HttpClient = HttpClient(CIO) { install(WebSockets) } + + private val rendezvousChannel = Channel() + + private val blockCountRequest = "{ \"jsonrpc\": \"2.0\", \"id\": \"1\", \"method\": \"DERO.GetBlockCount\" }" + + suspend fun start() { + val node = foundationNode + client.webSocket(host = node.host, port = node.port, path = node.path) { + writeMessages() + readMessages() + } + } + + fun stop() { + client.close() + } + + private suspend fun DefaultClientWebSocketSession.readMessages() { + incoming.receiveAsFlow().collect { message -> + (message as? Frame.Text)?.let { textFrame -> + val text = textFrame.readText() + println(text) + if (text.contains("\"method\":\"Block\"")) { + rendezvousChannel.send(true) + } + } + } + } + + private suspend fun DefaultClientWebSocketSession.writeMessages() { + rendezvousChannel.receiveAsFlow().onEach { + println("Prepared to send...") + outgoing.send(Frame.Text(blockCountRequest)) + }.launchIn(this) + } +}