support data field in error response
This commit is contained in:
Submodule emerald-grpc updated: 45b1c29d51...ce401bcd90
@@ -116,7 +116,7 @@ abstract class BaseHandler(
|
|||||||
// If Proxy is configured to preserve original order it means that a client expect responses at exact same position
|
// If Proxy is configured to preserve original order it means that a client expect responses at exact same position
|
||||||
// as requests even if a request completely failed for a some reason. It's very unlikely situation, but still possible
|
// as requests even if a request completely failed for a some reason. It's very unlikely situation, but still possible
|
||||||
// At this case, if we found a gap in responses, we put a default response with an error
|
// At this case, if we found a gap in responses, we put a default response with an error
|
||||||
?: NativeCall.CallResult(id, null, null, NativeCall.CallError(id, "No response", null), null, null, null)
|
?: NativeCall.CallResult(id, null, null, NativeCall.CallError(id, "No response", null, null), null, null, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.flatMapMany {
|
.flatMapMany {
|
||||||
|
|||||||
@@ -203,7 +203,12 @@ open class NativeCall(
|
|||||||
.setId(it.id)
|
.setId(it.id)
|
||||||
if (it.isError()) {
|
if (it.isError()) {
|
||||||
it.error?.let { error ->
|
it.error?.let { error ->
|
||||||
result.setErrorMessage(error.message).setErrorCode(error.id)
|
result.setErrorMessage(error.message)
|
||||||
|
.setErrorCode(error.id)
|
||||||
|
|
||||||
|
error.data?.let { data ->
|
||||||
|
result.setErrorData(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.payload = ByteString.copyFrom(it.result)
|
result.payload = ByteString.copyFrom(it.result)
|
||||||
@@ -301,7 +306,8 @@ open class NativeCall(
|
|||||||
CallError(
|
CallError(
|
||||||
requestItem.id,
|
requestItem.id,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
JsonRpcError(RpcResponseError.CODE_METHOD_NOT_EXIST, errorMessage)
|
JsonRpcError(RpcResponseError.CODE_METHOD_NOT_EXIST, errorMessage),
|
||||||
|
null
|
||||||
),
|
),
|
||||||
requestId,
|
requestId,
|
||||||
requestCount
|
requestCount
|
||||||
@@ -409,7 +415,7 @@ open class NativeCall(
|
|||||||
counter.get().let { attempts ->
|
counter.get().let { attempts ->
|
||||||
CallResult.fail(
|
CallResult.fail(
|
||||||
ctx.id, ctx.nonce,
|
ctx.id, ctx.nonce,
|
||||||
CallError(1, "No response or no available upstream for ${ctx.payload.method}", null),
|
CallError(1, "No response or no available upstream for ${ctx.payload.method}", null, null),
|
||||||
ctx
|
ctx
|
||||||
).also {
|
).also {
|
||||||
countFailure(attempts, ctx)
|
countFailure(attempts, ctx)
|
||||||
@@ -592,20 +598,33 @@ open class NativeCall(
|
|||||||
|
|
||||||
open class CallFailure(val id: Int, val reason: Throwable) : Exception("Failed to call $id: ${reason.message}")
|
open class CallFailure(val id: Int, val reason: Throwable) : Exception("Failed to call $id: ${reason.message}")
|
||||||
|
|
||||||
open class CallError(val id: Int, val message: String, val upstreamError: JsonRpcError?) {
|
open class CallError(val id: Int, val message: String, val upstreamError: JsonRpcError?, val data: String?) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
private val log = LoggerFactory.getLogger(CallError::class.java)
|
||||||
|
private fun getDataAsSting(details: Any?): String? {
|
||||||
|
return when (details) {
|
||||||
|
is String -> details
|
||||||
|
null -> null
|
||||||
|
else -> {
|
||||||
|
log.debug("Unsupported error details: {}", details)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fun from(t: Throwable): CallError {
|
fun from(t: Throwable): CallError {
|
||||||
return when (t) {
|
return when (t) {
|
||||||
is JsonRpcException -> CallError(t.id.asNumber().toInt(), t.error.message, t.error)
|
is JsonRpcException -> CallError(t.id.asNumber().toInt(), t.error.message, t.error, getDataAsSting(t.error.details))
|
||||||
is RpcException -> CallError(t.code, t.rpcMessage, null)
|
is RpcException -> CallError(t.code, t.rpcMessage, null, getDataAsSting(t.details))
|
||||||
is CallFailure -> CallError(t.id, t.reason.message ?: "Upstream Error", null)
|
is CallFailure -> CallError(t.id, t.reason.message ?: "Upstream Error", null, null)
|
||||||
else -> {
|
else -> {
|
||||||
// May only happen if it's an unhandled exception.
|
// May only happen if it's an unhandled exception.
|
||||||
// In this case try to find a meaningless details in the stack. Most important reason for doing that is to find an ID of the request
|
// In this case try to find a meaningless details in the stack. Most important reason for doing that is to find an ID of the request
|
||||||
if (t.cause != null) {
|
if (t.cause != null) {
|
||||||
from(t.cause!!)
|
from(t.cause!!)
|
||||||
} else {
|
} else {
|
||||||
CallError(1, t.message ?: "Upstream Error", null)
|
CallError(1, t.message ?: "Upstream Error", null, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ package io.emeraldpay.dshackle.upstream.rpcclient
|
|||||||
|
|
||||||
import io.emeraldpay.etherjar.rpc.RpcException
|
import io.emeraldpay.etherjar.rpc.RpcException
|
||||||
|
|
||||||
class JsonRpcError(val code: Int, val message: String, val details: Any?) {
|
data class JsonRpcError(val code: Int, val message: String, val details: Any?) {
|
||||||
|
|
||||||
constructor(code: Int, message: String) : this(code, message, null)
|
constructor(code: Int, message: String) : this(code, message, null)
|
||||||
|
|
||||||
@@ -33,26 +33,4 @@ class JsonRpcError(val code: Int, val message: String, val details: Any?) {
|
|||||||
fun asException(id: JsonRpcResponse.Id?): JsonRpcException {
|
fun asException(id: JsonRpcResponse.Id?): JsonRpcException {
|
||||||
return JsonRpcException(id ?: JsonRpcResponse.NumberId(-1), this, false)
|
return JsonRpcException(id ?: JsonRpcResponse.NumberId(-1), this, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (other !is JsonRpcError) return false
|
|
||||||
|
|
||||||
if (code != other.code) return false
|
|
||||||
if (message != other.message) return false
|
|
||||||
if (details != other.details) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = code
|
|
||||||
result = 31 * result + message.hashCode()
|
|
||||||
result = 31 * result + (details?.hashCode() ?: 0)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "JsonRpcError(code=$code, message='$message', details=$details)"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class WriteRpcJsonSpec extends Specification {
|
|||||||
def call = new ProxyCall(ProxyCall.RpcType.SINGLE)
|
def call = new ProxyCall(ProxyCall.RpcType.SINGLE)
|
||||||
call.ids[1] = 1
|
call.ids[1] = 1
|
||||||
def data = [
|
def data = [
|
||||||
new NativeCall.CallResult(1, null, null, new NativeCall.CallError(1, "Internal Error", null), null, null, null)
|
new NativeCall.CallResult(1, null, null, new NativeCall.CallError(1, "Internal Error", null, null), null, null, null)
|
||||||
]
|
]
|
||||||
when:
|
when:
|
||||||
def act = writer.toJson(call, data[0])
|
def act = writer.toJson(call, data[0])
|
||||||
@@ -127,7 +127,7 @@ class WriteRpcJsonSpec extends Specification {
|
|||||||
call.ids[3] = 15
|
call.ids[3] = 15
|
||||||
def data = [
|
def data = [
|
||||||
new NativeCall.CallResult(1, null, '"0x98dbb1"'.bytes, null, null, null, null),
|
new NativeCall.CallResult(1, null, '"0x98dbb1"'.bytes, null, null, null, null),
|
||||||
new NativeCall.CallResult(2, null, null, new NativeCall.CallError(2, "oops", null), null, null, null),
|
new NativeCall.CallResult(2, null, null, new NativeCall.CallError(2, "oops", null, null), null, null, null),
|
||||||
new NativeCall.CallResult(3, null, '{"hash": "0x2484f459dc"}'.bytes, null, null, null, null),
|
new NativeCall.CallResult(3, null, '{"hash": "0x2484f459dc"}'.bytes, null, null, null, null),
|
||||||
]
|
]
|
||||||
when:
|
when:
|
||||||
|
|||||||
Reference in New Issue
Block a user