Improved handling of invalid responses; Handle seq[byte] results such as `eth_getCode`

This commit is contained in:
Zahary Karadjov 2020-06-19 16:33:44 +03:00
parent 8c1a8ef8d9
commit 244254632b
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
3 changed files with 35 additions and 13 deletions

View File

@ -1,8 +1,12 @@
import tables, json, macros import
import chronos tables, json, macros,
chronos,
jsonmarshal, errors
from strutils import toLowerAscii from strutils import toLowerAscii
import jsonmarshal
export chronos export
chronos
type type
ClientId* = int64 ClientId* = int64
@ -60,7 +64,8 @@ proc processMessage*(self: RpcClient, line: string) {.gcsafe.} =
if "id" in node: if "id" in node:
let id = checkGet(node, "id", JInt) let id = checkGet(node, "id", JInt)
if not self.awaiting.hasKey(id): var requestFut: Future[Response]
if not self.awaiting.pop(id, requestFut):
raise newException(ValueError, raise newException(ValueError,
"Cannot find message id \"" & $node["id"].getInt & "\"") "Cannot find message id \"" & $node["id"].getInt & "\"")
@ -73,12 +78,12 @@ proc processMessage*(self: RpcClient, line: string) {.gcsafe.} =
if errorNode.isNil or errorNode.kind == JNull: if errorNode.isNil or errorNode.kind == JNull:
var res = node{"result"} var res = node{"result"}
if not res.isNil: if not res.isNil:
self.awaiting[id].complete((false, res)) requestFut.complete((false, res))
self.awaiting.del(id)
# TODO: actions on unable find result node
else: else:
self.awaiting[id].fail(newException(ValueError, $errorNode)) requestFut.fail(newException(InvalidResponse, "Missing `result` field"))
self.awaiting.del(id) else:
requestFut.fail(newException(ValueError, $errorNode))
elif "method" in node: elif "method" in node:
# This could be subscription notification # This could be subscription notification
let name = node["method"].getStr() let name = node["method"].getStr()
@ -175,9 +180,9 @@ proc createRpcFromSig*(clientType, rpcDecl: NimNode): NimNode =
callBody.add(jsonToNim(procRes, returnType, jsonRpcResult, "result")) callBody.add(jsonToNim(procRes, returnType, jsonRpcResult, "result"))
else: else:
# native json expected so no work # native json expected so no work
callBody.add(quote do: callBody.add quote do:
`procRes` = `rpcResult`.result `procRes` = `rpcResult`.result
)
when defined(nimDumpRpcs): when defined(nimDumpRpcs):
echo pathStr, ":\n", result.repr echo pathStr, ":\n", result.repr

10
json_rpc/errors.nim Normal file
View File

@ -0,0 +1,10 @@
type
JsonRpcError* = object of CatchableError
## Base type of all nim-json-rpc errors
ErrorResponse* = object of JsonRpcError
## raised when the server responded with an error
InvalidResponse* = object of JsonRpcError
## raised when the server response violates the JSON-RPC protocol

View File

@ -1,4 +1,6 @@
import macros, json, options, typetraits import
macros, json, options, typetraits,
stew/byteutils
proc expect*(actual, expected: JsonNodeKind, argName: string) = proc expect*(actual, expected: JsonNodeKind, argName: string) =
if actual != expected: raise newException(ValueError, "Parameter [" & argName & "] expected " & $expected & " but got " & $actual) if actual != expected: raise newException(ValueError, "Parameter [" & argName & "] expected " & $expected & " but got " & $actual)
@ -111,6 +113,11 @@ proc fromJson*(n: JsonNode, argName: string, result: var string) =
result = n.getStr() result = n.getStr()
proc fromJson*[T](n: JsonNode, argName: string, result: var seq[T]) = proc fromJson*[T](n: JsonNode, argName: string, result: var seq[T]) =
when T is byte:
if n.kind == JString:
result = hexToSeqByte n.getStr()
return
n.kind.expect(JArray, argName) n.kind.expect(JArray, argName)
result = newSeq[T](n.len) result = newSeq[T](n.len)
for i in 0 ..< n.len: for i in 0 ..< n.len: