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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

- This is **Kogmios**, a Kotlin client library for the Ogmios WebSocket interface
- Single-module Gradle project (Kotlin DSL) targeting Java 21
- Core tech: Kotlin 2.x, Ktor client (CIO + websockets), kotlinx-serialization, coroutines
- Core tech: Kotlin 2.x, Ktor client (CIO + websockets), Jackson, coroutines
- Domain: Cardano/Ogmios JSON-WSP protocol messages mapped to typed models

## CI Pipeline Context
Expand Down
11 changes: 6 additions & 5 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
java
id("com.github.ben-manes.versions") version Versions.VERSIONS_PLUGIN
id("io.github.ben-manes.versions") version Versions.VERSIONS_PLUGIN
id("org.jlleitschuh.gradle.ktlint") version Versions.KTLINT_PLUGIN
kotlin("jvm") version Versions.KOTLIN
kotlin("plugin.serialization") version Versions.KOTLIN
id("signing")
id("com.vanniktech.maven.publish") version Versions.MAVEN_PUBLISH
}

group = "io.newm"
version = "2.7.1-SNAPSHOT"
version = "3.0.0-SNAPSHOT"

java.sourceCompatibility = JavaVersion.VERSION_21
java.targetCompatibility = JavaVersion.VERSION_21
Expand All @@ -36,7 +35,10 @@ dependencies {
implementation("ch.qos.logback:logback-classic:${Versions.LOGBACK}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.COROUTINES}")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:${Versions.COROUTINES}")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.KOTLINX_SERIALIZATION}")
implementation(platform("com.fasterxml.jackson:jackson-bom:${Versions.JACKSON}"))
implementation("com.fasterxml.jackson.core:jackson-databind")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect:${Versions.KOTLIN}")

implementation("org.apache.commons:commons-numbers-fraction:${Versions.COMMONS_NUMBERS}")

Expand Down Expand Up @@ -126,7 +128,6 @@ tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
listOf(
"-Xjsr305=strict",
"-opt-in=kotlin.RequiresOptIn",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-opt-in=kotlin.time.ExperimentalTime",
)
Expand Down
24 changes: 12 additions & 12 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
object Versions {
const val COMMONS_LOGGING = "1.3.5"
const val COMMONS_NUMBERS = "1.2"
const val COROUTINES = "1.10.2"
const val COMMONS_LOGGING = "1.4.0"
const val COMMONS_NUMBERS = "1.3"
const val COROUTINES = "1.11.0"
const val GOOGLE_TRUTH = "1.4.5"
const val JUNIT = "6.0.2"
const val JUNIT_PLATFORM = "6.0.2"
const val KOTLIN = "2.3.0"
const val KOTLINX_SERIALIZATION = "1.10.0"
const val JUNIT = "6.1.3"
const val JUNIT_PLATFORM = "6.1.3"
const val KOTLIN = "2.4.20"
const val JACKSON = "2.22.2"
const val KTLINT = "1.8.0"
const val KTLINT_PLUGIN = "14.0.1"
const val KTOR = "3.4.0"
const val LOGBACK = "1.5.27"
const val MOCKK = "1.14.9"
const val MAVEN_PUBLISH = "0.36.0"
const val VERSIONS_PLUGIN = "0.53.0"
const val KTOR = "3.6.0"
const val LOGBACK = "1.6.3"
const val MOCKK = "1.14.11"
const val MAVEN_PUBLISH = "0.37.0"
const val VERSIONS_PLUGIN = "0.63.1"
}
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
44 changes: 4 additions & 40 deletions src/main/kotlin/io/newm/kogmios/ClientImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import io.newm.kogmios.protocols.messages.MsgQueryGenesisConfigResponse
import io.newm.kogmios.protocols.messages.MsgQueryLiveStakeDistributionResponse
import io.newm.kogmios.protocols.messages.MsgQueryNetworkStartTimeResponse
import io.newm.kogmios.protocols.messages.MsgQueryProjectedRewardsResponse
import io.newm.kogmios.protocols.messages.MsgQueryProposedProtocolParametersResponse
import io.newm.kogmios.protocols.messages.MsgQueryProtocolParametersResponse
import io.newm.kogmios.protocols.messages.MsgQueryRewardAccountSummariesResponse
import io.newm.kogmios.protocols.messages.MsgQueryStakePoolsResponse
Expand Down Expand Up @@ -78,10 +77,8 @@ import io.newm.kogmios.protocols.model.StakePool
import io.newm.kogmios.protocols.model.fault.InternalErrorFault
import io.newm.kogmios.protocols.model.fault.StringFaultData
import io.newm.kogmios.protocols.model.result.HealthResult
import io.newm.kogmios.serializers.BigFractionSerializer
import io.newm.kogmios.serializers.BigIntegerSerializer
import io.newm.kogmios.serializers.OgmiosJson
import java.io.IOException
import java.math.BigInteger
import java.util.concurrent.ConcurrentHashMap
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.cancellation.CancellationException
Expand All @@ -104,9 +101,6 @@ import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withTimeout
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import org.apache.commons.numbers.fraction.BigFraction
import org.slf4j.LoggerFactory

internal class ClientImpl(
Expand Down Expand Up @@ -159,7 +153,7 @@ internal class ClientImpl(
return Frame.Text(
when (value) {
is JsonRpcRequest -> {
json.encodeToString(value).also {
OgmiosJson.mapper.writeValueAsString(value).also {
// temporary while we need to figure out how all the requests look
log.debug("sending: {}", it)
}
Expand All @@ -186,7 +180,7 @@ internal class ClientImpl(
val jsonString = (content as Frame.Text).readText()
log.debug("received: {}", jsonString)
return try {
json.decodeFromString<JsonRpcResponse>(jsonString)
OgmiosJson.mapper.readValue(jsonString, JsonRpcResponse::class.java)
} catch (e: Throwable) {
// This should never happen unless WE have made an error in our parsers somewhere.
val idRegex =
Expand Down Expand Up @@ -539,20 +533,6 @@ internal class ClientImpl(
}
}

override suspend fun proposedProtocolParameters(timeoutMs: Long): MsgQueryProposedProtocolParametersResponse {
assertConnected()
val message =
MsgQuery(
method = MsgQuery.METHOD_QUERY_LEDGER_STATE_PROPOSED_PROTOCOL_PARAMETERS,
)
sendQueue.send(message)
return coroutineScope {
withTimeout(timeoutMs) {
message.completableDeferred.await() as MsgQueryProposedProtocolParametersResponse
}
}
}

override suspend fun liveStakeDistribution(timeoutMs: Long): MsgQueryLiveStakeDistributionResponse {
assertConnected()
val message =
Expand Down Expand Up @@ -602,7 +582,7 @@ internal class ClientImpl(
override suspend fun health(): HealthResult {
val response = httpClient.get("http://$websocketHost:$websocketPort/health")
val jsonBody = response.bodyAsText()
return json.decodeFromString(jsonBody)
return OgmiosJson.mapper.readValue(jsonBody, HealthResult::class.java)
}

override suspend fun acquireMempool(timeoutMs: Long): MsgAcquireMempoolResponse {
Expand Down Expand Up @@ -764,20 +744,4 @@ internal class ClientImpl(
override val coroutineContext: CoroutineContext by lazy {
job + Dispatchers.IO + DefaultCoroutineExceptionHandler(log)
}

companion object {
internal val json =
Json {
// classDiscriminator = "type"
encodeDefaults = true
explicitNulls = true
ignoreUnknownKeys = true
isLenient = true
serializersModule =
SerializersModule {
contextual(BigInteger::class, BigIntegerSerializer)
contextual(BigFraction::class, BigFractionSerializer)
}
}
}
}
6 changes: 0 additions & 6 deletions src/main/kotlin/io/newm/kogmios/StateQueryClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import io.newm.kogmios.protocols.messages.MsgQueryGenesisConfigResponse
import io.newm.kogmios.protocols.messages.MsgQueryLiveStakeDistributionResponse
import io.newm.kogmios.protocols.messages.MsgQueryNetworkStartTimeResponse
import io.newm.kogmios.protocols.messages.MsgQueryProjectedRewardsResponse
import io.newm.kogmios.protocols.messages.MsgQueryProposedProtocolParametersResponse
import io.newm.kogmios.protocols.messages.MsgQueryProtocolParametersResponse
import io.newm.kogmios.protocols.messages.MsgQueryRewardAccountSummariesResponse
import io.newm.kogmios.protocols.messages.MsgQueryStakePoolsResponse
Expand Down Expand Up @@ -108,11 +107,6 @@ interface StateQueryClient : Client {
timeoutMs: Long = LONG_REQUEST_TIMEOUT_MS
): MsgQueryProjectedRewardsResponse

/**
* Get proposed protocol parameters for update, if any.
*/
suspend fun proposedProtocolParameters(timeoutMs: Long = DEFAULT_REQUEST_TIMEOUT_MS): MsgQueryProposedProtocolParametersResponse

/**
* Get the current stake pool distribution. This request may be quite long, use with care.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
package io.newm.kogmios.protocols.messages

import com.fasterxml.jackson.annotation.JsonProperty

import com.fasterxml.jackson.annotation.JsonIgnore
import io.newm.kogmios.protocols.model.fault.Fault
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient

/**
* Container for an error response from Ogmios
*/
@Serializable
data class JsonRpcErrorResponse(
@SerialName("error")
@param:JsonProperty(value = "error", required = true)
@get:JsonProperty("error")
val error: Fault,
@SerialName("id")
@param:JsonProperty(value = "id", required = true)
@get:JsonProperty("id")
override val id: String,
@Transient
@get:JsonIgnore
val cause: Throwable? = null,
) : JsonRpcResponse()
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
package io.newm.kogmios.protocols.messages

import com.fasterxml.jackson.annotation.JsonIgnore
import io.newm.kogmios.protocols.Const.JSONRPC_VERSION
import kotlinx.coroutines.CompletableDeferred
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient

/**
* Base class for all Ogmios requests
*/
@Serializable
sealed class JsonRpcRequest {
@SerialName("jsonrpc")
val jsonrpc: String = JSONRPC_VERSION

@SerialName("method")
abstract val method: String

@SerialName("id")
abstract val id: String

@Transient
@get:JsonIgnore
val completableDeferred: CompletableDeferred<JsonRpcSuccessResponse> = CompletableDeferred()
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
package io.newm.kogmios.protocols.messages

import io.newm.kogmios.protocols.Const.JSONRPC_VERSION
import io.newm.kogmios.serializers.JsonRpcResponseSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Base class for all Ogmios responses.
*/
@Serializable(with = JsonRpcResponseSerializer::class)
sealed class JsonRpcResponse {
@SerialName("jsonrpc")
val jsonrpc: String = JSONRPC_VERSION

@SerialName("id")
abstract val id: String
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
package io.newm.kogmios.protocols.messages

import io.newm.kogmios.protocols.model.result.IgnoredOgmiosResult
import com.fasterxml.jackson.annotation.JsonTypeInfo
import io.newm.kogmios.protocols.model.result.OgmiosResult
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.json.JsonClassDiscriminator

/**
* Container for a success response from Ogmios
*/
@Serializable
@JsonClassDiscriminator("method")
sealed class JsonRpcSuccessResponse(
@Transient
open val result: OgmiosResult = IgnoredOgmiosResult,
) : JsonRpcResponse()
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "method")
sealed class JsonRpcSuccessResponse : JsonRpcResponse() {
abstract val result: OgmiosResult
}
12 changes: 6 additions & 6 deletions src/main/kotlin/io/newm/kogmios/protocols/messages/MsgAcquire.kt
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
package io.newm.kogmios.protocols.messages

import com.fasterxml.jackson.annotation.JsonProperty

import io.newm.kogmios.protocols.model.PointOrOrigin
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

import java.util.UUID

/**
* Acquire a ledger state for the Local State Query miniprotocol. If you don't specify a ChainPoint argument,
* the ledger tip will be acquired.
*/
@Serializable

data class MsgAcquire(
@SerialName("method")
override val method: String = METHOD_NAME,
@SerialName("params")
@param:JsonProperty(value = "params", required = true)
@get:JsonProperty("params")
val params: PointOrOrigin,
@SerialName("id")
override val id: String = "$METHOD_NAME: ${UUID.randomUUID()}",
) : JsonRpcRequest() {
companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package io.newm.kogmios.protocols.messages

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.util.UUID

/**
* Acquire a mempool snapshot
*/
@Serializable

data class MsgAcquireMempool(
@SerialName("method")
override val method: String = METHOD_NAME,
@SerialName("id")
override val id: String = "$method: ${UUID.randomUUID()}",
) : JsonRpcRequest() {
companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package io.newm.kogmios.protocols.messages

import com.fasterxml.jackson.annotation.JsonProperty

import com.fasterxml.jackson.annotation.JsonTypeName

import io.newm.kogmios.protocols.model.result.AcquireMempoolResult
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
* Response that comes back from Ogmios after an AwaitAcquire message is sent.
*/
@Serializable
@SerialName(MsgAcquireMempool.METHOD_NAME)

@JsonTypeName(MsgAcquireMempool.METHOD_NAME)
data class MsgAcquireMempoolResponse(
@SerialName("result")
@param:JsonProperty(value = "result", required = true)
@get:JsonProperty("result")
override val result: AcquireMempoolResult,
@SerialName("id")
@param:JsonProperty(value = "id", required = true)
@get:JsonProperty("id")
override val id: String,
) : JsonRpcSuccessResponse()
Loading
Loading