diff --git a/json_rpc/client.nim b/json_rpc/client.nim index bde73b1..3ce3f40 100644 --- a/json_rpc/client.nim +++ b/json_rpc/client.nim @@ -1,8 +1,12 @@ -import tables, json, macros -import chronos +import + tables, json, macros, + chronos, + jsonmarshal, errors + from strutils import toLowerAscii -import jsonmarshal -export chronos + +export + chronos type ClientId* = int64 @@ -60,7 +64,8 @@ proc processMessage*(self: RpcClient, line: string) {.gcsafe.} = if "id" in node: 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, "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: var res = node{"result"} if not res.isNil: - self.awaiting[id].complete((false, res)) - self.awaiting.del(id) - # TODO: actions on unable find result node + requestFut.complete((false, res)) + else: + requestFut.fail(newException(InvalidResponse, "Missing `result` field")) else: - self.awaiting[id].fail(newException(ValueError, $errorNode)) - self.awaiting.del(id) + requestFut.fail(newException(ValueError, $errorNode)) + elif "method" in node: # This could be subscription notification let name = node["method"].getStr() @@ -175,9 +180,9 @@ proc createRpcFromSig*(clientType, rpcDecl: NimNode): NimNode = callBody.add(jsonToNim(procRes, returnType, jsonRpcResult, "result")) else: # native json expected so no work - callBody.add(quote do: + callBody.add quote do: `procRes` = `rpcResult`.result - ) + when defined(nimDumpRpcs): echo pathStr, ":\n", result.repr diff --git a/json_rpc/errors.nim b/json_rpc/errors.nim new file mode 100644 index 0000000..40b58de --- /dev/null +++ b/json_rpc/errors.nim @@ -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 + diff --git a/json_rpc/jsonmarshal.nim b/json_rpc/jsonmarshal.nim index 97f711d..7c4c00b 100644 --- a/json_rpc/jsonmarshal.nim +++ b/json_rpc/jsonmarshal.nim @@ -1,4 +1,6 @@ -import macros, json, options, typetraits +import + macros, json, options, typetraits, + stew/byteutils proc expect*(actual, expected: JsonNodeKind, argName: string) = 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() 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) result = newSeq[T](n.len) for i in 0 ..< n.len: