support data field in error response

This commit is contained in:
a10zn8
2023-06-06 17:08:57 +04:00
committed by GitHub
parent 0db052024b
commit df8586258f
5 changed files with 32 additions and 35 deletions

View File

@@ -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
// 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
?: 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 {

View File

@@ -203,7 +203,12 @@ open class NativeCall(
.setId(it.id)
if (it.isError()) {
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 {
result.payload = ByteString.copyFrom(it.result)
@@ -301,7 +306,8 @@ open class NativeCall(
CallError(
requestItem.id,
errorMessage,
JsonRpcError(RpcResponseError.CODE_METHOD_NOT_EXIST, errorMessage)
JsonRpcError(RpcResponseError.CODE_METHOD_NOT_EXIST, errorMessage),
null
),
requestId,
requestCount
@@ -409,7 +415,7 @@ open class NativeCall(
counter.get().let { attempts ->
CallResult.fail(
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
).also {
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 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 {
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 {
return when (t) {
is JsonRpcException -> CallError(t.id.asNumber().toInt(), t.error.message, t.error)
is RpcException -> CallError(t.code, t.rpcMessage, null)
is CallFailure -> CallError(t.id, t.reason.message ?: "Upstream Error", null)
is JsonRpcException -> CallError(t.id.asNumber().toInt(), t.error.message, t.error, getDataAsSting(t.error.details))
is RpcException -> CallError(t.code, t.rpcMessage, null, getDataAsSting(t.details))
is CallFailure -> CallError(t.id, t.reason.message ?: "Upstream Error", null, null)
else -> {
// 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
if (t.cause != null) {
from(t.cause!!)
} else {
CallError(1, t.message ?: "Upstream Error", null)
CallError(1, t.message ?: "Upstream Error", null, null)
}
}
}

View File

@@ -17,7 +17,7 @@ package io.emeraldpay.dshackle.upstream.rpcclient
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)
@@ -33,26 +33,4 @@ class JsonRpcError(val code: Int, val message: String, val details: Any?) {
fun asException(id: JsonRpcResponse.Id?): JsonRpcException {
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)"
}
}

View File

@@ -98,7 +98,7 @@ class WriteRpcJsonSpec extends Specification {
def call = new ProxyCall(ProxyCall.RpcType.SINGLE)
call.ids[1] = 1
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:
def act = writer.toJson(call, data[0])
@@ -127,7 +127,7 @@ class WriteRpcJsonSpec extends Specification {
call.ids[3] = 15
def data = [
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),
]
when: