Skip to content

Commit aab3db8

Browse files
committed
problem: Kotlin RPC layer always comes with Ktor
solution: move Kotlin RPC based classes to a separate module
1 parent 3a32b27 commit aab3db8

17 files changed

Lines changed: 193 additions & 115 deletions

File tree

‎README.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,16 @@ Structure of dependencies between modules:
2828
* `etherjar-hex`
2929
* `etherjar-rpc-emerald`
3030
* `etherjar-rpc-api`
31+
* `etherjar-rpc-kotlin`
32+
* `etherjar-rpc-api`
33+
* `etherjar-rpc-json`
3134
* `etherjar-rpc-emerald-kotlin`
3235
* `etherjar-rpc-api`
33-
* `etherjar-rpc-http-ktor`
36+
* `etherjar-rpc-kotlin`
3437
* `etherjar-rpc-http-ktor`
3538
* `etherjar-rpc-api`
3639
* `etherjar-rpc-json`
40+
* `etherjar-rpc-kotlin`
3741
* `etherjar-rpc-http`
3842
* `etherjar-rpc-api`
3943
* `etherjar-domain`
@@ -68,7 +72,8 @@ where
6872
* `etherjar-rpc-json` - JSON mapping to/from Java objects
6973
* `etherjar-rpc-api` - [JSON-RPC API](https://github.com/ethereum/wiki/wiki/JSON-RPC) generic
7074
implementation
71-
* `etherjar-rpc-http-ktor` - Kotlin with coroutines transport implementation for JSON-RPC API data-layer
75+
* `etherjar-rpc-kotlin` - Kotlin coroutines client for JSON-RPC API data-layer
76+
* `etherjar-rpc-http-ktor` - Ktor based Kotlin coroutines transport for JSON-RPC API data-layer
7277
* `etherjar-rpc-emerald` - gRPC transport,
7378
see [Emerald Dshackle](https://github.com/emeraldpay/dshackle)
7479
* `etherjar-rpc-emerald-kotlin` - Kotlin coroutines gRPC transport for Emerald API

‎etherjar-rpc-emerald-kotlin/build.gradle‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ repositories {
2222

2323
dependencies {
2424
api project(':etherjar-rpc-api')
25-
api project(':etherjar-rpc-http-ktor')
25+
api project(':etherjar-rpc-kotlin')
2626
api ("io.emeraldpay:emerald-api:0.13.0") {
2727
exclude group: "io.grpc"
2828
}
@@ -44,4 +44,4 @@ dependencies {
4444
testImplementation "io.kotest:kotest-runner-junit5:5.9.1"
4545
testImplementation "io.kotest:kotest-assertions-core:5.9.1"
4646
testImplementation "io.mockk:mockk:1.13.12"
47-
}
47+
}

‎etherjar-rpc-emerald-kotlin/src/main/kotlin/io/emeraldpay/etherjar/rpc/emerald/EmeraldKotlinTransport.kt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import io.emeraldpay.api.proto.BlockchainOuterClass
2222
import io.emeraldpay.api.proto.Common
2323
import io.emeraldpay.api.Chain
2424
import io.emeraldpay.etherjar.rpc.*
25-
import io.emeraldpay.etherjar.rpc.ktor.CoroutineRpcTransport
26-
import io.emeraldpay.etherjar.rpc.ktor.CoroutineBatchItem
25+
import io.emeraldpay.etherjar.rpc.kotlin.CoroutineRpcTransport
26+
import io.emeraldpay.etherjar.rpc.kotlin.CoroutineBatchItem
2727
import io.grpc.Channel
2828
import io.grpc.ClientInterceptor
2929
import io.grpc.ManagedChannel

‎etherjar-rpc-emerald-kotlin/src/test/kotlin/io/emeraldpay/etherjar/rpc/emerald/EmeraldKotlinTransportTest.kt‎

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,29 @@ import io.emeraldpay.api.proto.BlockchainGrpc
2121
import io.emeraldpay.api.proto.BlockchainOuterClass
2222
import io.emeraldpay.etherjar.rpc.Conversion
2323
import io.emeraldpay.etherjar.rpc.RpcCall
24-
import io.emeraldpay.etherjar.rpc.ktor.CoroutineBatchItem
24+
import io.emeraldpay.etherjar.rpc.kotlin.CoroutineBatchItem
2525
import io.grpc.stub.StreamObserver
2626
import io.kotest.core.spec.style.ShouldSpec
2727
import io.kotest.matchers.shouldBe
2828
import io.kotest.matchers.shouldNotBe
2929
import kotlinx.coroutines.test.runTest
3030

3131
class EmeraldKotlinTransportTest : ShouldSpec({
32-
32+
3333
should("convert to correct Protobuf") {
3434
val transport = EmeraldKotlinTransport.newBuilder()
3535
.connectTo("localhost:2449")
3636
.chain(Chain.ETHEREUM)
3737
.build()
38-
38+
3939
val items = listOf(
4040
CoroutineBatchItem(RpcCall.create("eth_test", Int::class.java), 1),
4141
CoroutineBatchItem(RpcCall.create("eth_test2", Int::class.java, listOf("test", 14)), 2)
4242
)
43-
43+
4444
val idMapping = mutableMapOf<Int, CoroutineBatchItem<*, *>>()
4545
val request = transport.convert(items, idMapping)
46-
46+
4747
val expected = BlockchainOuterClass.NativeCallRequest.newBuilder()
4848
.setChainValue(Chain.ETHEREUM.id)
4949
.addItems(
@@ -59,33 +59,33 @@ class EmeraldKotlinTransportTest : ShouldSpec({
5959
.setPayload(ByteString.copyFromUtf8("[\"test\",14]"))
6060
)
6161
.build()
62-
62+
6363
request shouldBe expected
6464
transport.close()
6565
}
66-
66+
6767
should("throw exception on invalid param") {
6868
val transport = EmeraldKotlinTransport.newBuilder()
6969
.connectTo("localhost:2449")
7070
.chain(Chain.ETHEREUM)
7171
.build()
72-
72+
7373
val items = listOf(
7474
CoroutineBatchItem(RpcCall.create("eth_test", Int::class.java, listOf(Any())), 1)
7575
)
76-
76+
7777
val idMapping = mutableMapOf<Int, CoroutineBatchItem<*, *>>()
78-
78+
7979
try {
8080
transport.convert(items, idMapping)
8181
assert(false) { "Should have thrown exception" }
8282
} catch (e: Exception) {
8383
// Expected
8484
}
85-
85+
8686
transport.close()
8787
}
88-
88+
8989
should("use selector") {
9090
val selector = BlockchainOuterClass.Selector.newBuilder()
9191
.setAndSelector(
@@ -106,20 +106,20 @@ class EmeraldKotlinTransportTest : ShouldSpec({
106106
)
107107
)
108108
.build()
109-
109+
110110
val transport = EmeraldKotlinTransport.newBuilder()
111111
.connectTo("localhost:2449")
112112
.chain(Chain.ETHEREUM)
113113
.build()
114114
.copyWithSelector(selector)
115-
115+
116116
val items = listOf(
117117
CoroutineBatchItem(RpcCall.create("eth_test", Int::class.java, listOf("hello")), 1)
118118
)
119-
119+
120120
val idMapping = mutableMapOf<Int, CoroutineBatchItem<*, *>>()
121121
val request = transport.convert(items, idMapping)
122-
122+
123123
val expected = BlockchainOuterClass.NativeCallRequest.newBuilder()
124124
.setChainValue(Chain.ETHEREUM.id)
125125
.setSelector(selector)
@@ -130,25 +130,25 @@ class EmeraldKotlinTransportTest : ShouldSpec({
130130
.setPayload(ByteString.copyFromUtf8("[\"hello\"]"))
131131
)
132132
.build()
133-
133+
134134
request shouldBe expected
135135
transport.close()
136136
}
137-
137+
138138
should("redefine chain") {
139139
val transport = EmeraldKotlinTransport.newBuilder()
140140
.connectTo("localhost:2449")
141141
.chain(Chain.ETHEREUM)
142142
.build()
143143
.copyForChain(Chain.ETHEREUM_CLASSIC)
144-
144+
145145
val items = listOf(
146146
CoroutineBatchItem(RpcCall.create("eth_test", Int::class.java), 1)
147147
)
148-
148+
149149
val idMapping = mutableMapOf<Int, CoroutineBatchItem<*, *>>()
150150
val request = transport.convert(items, idMapping)
151-
151+
152152
val expected = BlockchainOuterClass.NativeCallRequest.newBuilder()
153153
.setChainValue(Chain.ETHEREUM_CLASSIC.id)
154154
.addItems(
@@ -158,23 +158,23 @@ class EmeraldKotlinTransportTest : ShouldSpec({
158158
.setPayload(ByteString.copyFromUtf8("[]"))
159159
)
160160
.build()
161-
161+
162162
request shouldBe expected
163163
transport.close()
164164
}
165-
165+
166166
should("make actual call") {
167167
runTest {
168168
var actualRequest: BlockchainOuterClass.NativeCallRequest? = null
169-
169+
170170
val mockImpl = object : BlockchainGrpc.BlockchainImplBase() {
171171
override fun nativeCall(
172172
request: BlockchainOuterClass.NativeCallRequest,
173173
responseObserver: StreamObserver<BlockchainOuterClass.NativeCallReplyItem>
174174
) {
175175
actualRequest = request
176176
println("requested $request")
177-
177+
178178
responseObserver.onNext(
179179
BlockchainOuterClass.NativeCallReplyItem.newBuilder()
180180
.setId(1)
@@ -185,32 +185,32 @@ class EmeraldKotlinTransportTest : ShouldSpec({
185185
responseObserver.onCompleted()
186186
}
187187
}
188-
188+
189189
val channel = MockServer.createChannelFor(mockImpl)
190190
val transport = EmeraldKotlinTransport.newBuilder()
191191
.connectUsing(channel)
192192
.chain(Chain.ETHEREUM)
193193
.build()
194-
194+
195195
val items = listOf(
196196
CoroutineBatchItem(
197197
RpcCall.create("eth_test").converted(Long::class.java, Conversion.asLong),
198198
1
199199
)
200200
)
201-
201+
202202
val result = transport.execute(items)
203-
203+
204204
result.size shouldBe 1
205205
result[0].error shouldBe null
206206
result[0].value shouldBe 0xab5461ca4b100L
207-
207+
208208
actualRequest shouldNotBe null
209-
209+
210210
transport.close()
211211
}
212212
}
213-
213+
214214
should("handle error response") {
215215
runTest {
216216
val mockImpl = object : BlockchainGrpc.BlockchainImplBase() {
@@ -228,24 +228,24 @@ class EmeraldKotlinTransportTest : ShouldSpec({
228228
responseObserver.onCompleted()
229229
}
230230
}
231-
231+
232232
val channel = MockServer.createChannelFor(mockImpl)
233233
val transport = EmeraldKotlinTransport.newBuilder()
234234
.connectUsing(channel)
235235
.chain(Chain.ETHEREUM)
236236
.build()
237-
237+
238238
val items = listOf(
239239
CoroutineBatchItem(RpcCall.create("eth_test", String::class.java), 1)
240240
)
241-
241+
242242
val result = transport.execute(items)
243-
243+
244244
result.size shouldBe 1
245245
result[0].error shouldNotBe null
246246
result[0].error!!.message shouldBe "RPC Error -32603: Test error"
247-
247+
248248
transport.close()
249249
}
250250
}
251-
})
251+
})

‎etherjar-rpc-http-ktor/build.gradle‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ compileTestKotlin {
3434
dependencies {
3535
api project(':etherjar-rpc-api')
3636
api project(':etherjar-rpc-json')
37+
api project(':etherjar-rpc-kotlin')
3738

3839
implementation 'org.jetbrains.kotlin:kotlin-stdlib:2.1.0'
3940
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1'

‎etherjar-rpc-http-ktor/src/main/kotlin/io/emeraldpay/etherjar/rpc/ktor/KtorRpcTransport.kt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package io.emeraldpay.etherjar.rpc.ktor
1818

1919
import com.fasterxml.jackson.databind.JavaType
2020
import io.emeraldpay.etherjar.rpc.*
21+
import io.emeraldpay.etherjar.rpc.kotlin.CoroutineBatchItem
22+
import io.emeraldpay.etherjar.rpc.kotlin.CoroutineRpcTransport
2123
import io.ktor.client.*
2224
import io.ktor.client.engine.cio.*
2325
import io.ktor.client.plugins.contentnegotiation.*

‎etherjar-rpc-http-ktor/src/test/kotlin/io/emeraldpay/etherjar/rpc/ktor/KtorRpcTransportTest.kt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.emeraldpay.etherjar.rpc.ktor
1818

1919
import io.emeraldpay.etherjar.rpc.*
20+
import io.emeraldpay.etherjar.rpc.kotlin.CoroutineBatchItem
2021
import io.kotest.core.spec.style.ShouldSpec
2122
import io.kotest.matchers.collections.shouldHaveSize
2223
import io.kotest.matchers.shouldBe

‎etherjar-rpc-kotlin/build.gradle‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2025 EmeraldPay Ltd, All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
plugins {
18+
id 'org.jetbrains.kotlin.jvm' version '2.1.0'
19+
}
20+
21+
compileKotlin {
22+
kotlinOptions {
23+
jvmTarget = '17'
24+
}
25+
}
26+
27+
compileTestKotlin {
28+
kotlinOptions {
29+
jvmTarget = '17'
30+
}
31+
}
32+
33+
dependencies {
34+
api project(':etherjar-rpc-api')
35+
api project(':etherjar-rpc-json')
36+
37+
implementation 'org.jetbrains.kotlin:kotlin-stdlib:2.1.0'
38+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1'
39+
40+
// Jackson dependencies (matching etherjar-rpc-json versions)
41+
implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8'
42+
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
43+
44+
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.1'
45+
testImplementation 'io.kotest:kotest-runner-junit5:5.9.1'
46+
testImplementation 'io.kotest:kotest-assertions-core:5.9.1'
47+
testImplementation 'io.mockk:mockk:1.13.12'
48+
}

etherjar-rpc-http-ktor/src/main/kotlin/io/emeraldpay/etherjar/rpc/ktor/CoroutineBatch.kt renamed to etherjar-rpc-kotlin/src/main/kotlin/io/emeraldpay/etherjar/rpc/kotlin/CoroutineBatch.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package io.emeraldpay.etherjar.rpc.ktor
17+
package io.emeraldpay.etherjar.rpc.kotlin
1818

1919
import io.emeraldpay.etherjar.rpc.RpcCall
2020
import io.emeraldpay.etherjar.rpc.RpcCallResponse

etherjar-rpc-http-ktor/src/main/kotlin/io/emeraldpay/etherjar/rpc/ktor/CoroutineBatchItem.kt renamed to etherjar-rpc-kotlin/src/main/kotlin/io/emeraldpay/etherjar/rpc/kotlin/CoroutineBatchItem.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package io.emeraldpay.etherjar.rpc.ktor
17+
package io.emeraldpay.etherjar.rpc.kotlin
1818

1919
import io.emeraldpay.etherjar.rpc.RpcCall
2020
import io.emeraldpay.etherjar.rpc.RpcException

0 commit comments

Comments
 (0)