diff --git a/json_rpc/client.nim b/json_rpc/client.nim index ea3437b..d8b1b18 100644 --- a/json_rpc/client.nim +++ b/json_rpc/client.nim @@ -27,7 +27,8 @@ proc rpcCallNode*(path: string, params: JsonNode, id: ClientId): JsonNode = %{"jsonrpc": %"2.0", "method": %path, "params": params, "id": %id} method call*(client: RpcClient, name: string, - params: JsonNode): Future[Response] {.gcsafe, async, base.} = discard + params: JsonNode): Future[Response] {.gcsafe, async, base.} = + discard method close*(client: RpcClient) {.base, gcsafe, async.} = discard diff --git a/json_rpc/clients/httpclient.nim b/json_rpc/clients/httpclient.nim index 777d6a1..a6aaf37 100644 --- a/json_rpc/clients/httpclient.nim +++ b/json_rpc/clients/httpclient.nim @@ -172,13 +172,12 @@ proc httpMethod*(client: RpcHttpClient, m: HttpMethod) = client.options.httpMethod = m method call*(client: RpcHttpClient, name: string, - params: JsonNode): Future[Response] {.async, gcsafe.} = + params: JsonNode): Future[Response] {.async, gcsafe.} = ## Remotely calls the specified RPC method. let id = client.getNextId() let transp = await connect(client.addresses[0]) var reqBody = $rpcCallNode(name, params, id) - echo "Sending (", client.httpMethod, "): ", reqBody let res = await transp.sendRequest(reqBody, client.httpMethod) if not res: debug "Failed to send message to RPC server", diff --git a/json_rpc/clients/socketclient.nim b/json_rpc/clients/socketclient.nim index 4357d9a..cfbd12c 100644 --- a/json_rpc/clients/socketclient.nim +++ b/json_rpc/clients/socketclient.nim @@ -14,7 +14,7 @@ proc newRpcSocketClient*: RpcSocketClient = result.initRpcClient() method call*(self: RpcSocketClient, name: string, - params: JsonNode): Future[Response] {.async.} = + params: JsonNode): Future[Response] {.async.} = ## Remotely calls the specified RPC method. let id = self.getNextId() var value = $rpcCallNode(name, params, id) & "\c\l" @@ -29,7 +29,7 @@ method call*(self: RpcSocketClient, name: string, let res = await self.transport.write(value) # TODO: Add actions when not full packet was send, e.g. disconnect peer. - doAssert(res == len(value)) + doAssert(res == len(value)) result = await newFut diff --git a/json_rpc/clients/websocketclient.nim b/json_rpc/clients/websocketclient.nim index 4924b54..000a767 100644 --- a/json_rpc/clients/websocketclient.nim +++ b/json_rpc/clients/websocketclient.nim @@ -15,7 +15,7 @@ proc newRpcWebSocketClient*: RpcWebSocketClient = result.initRpcClient() method call*(self: RpcWebSocketClient, name: string, - params: JsonNode): Future[Response] {.async.} = + params: JsonNode): Future[Response] {.async.} = ## Remotely calls the specified RPC method. let id = self.getNextId() var value = $rpcCallNode(name, params, id) & "\c\l" diff --git a/json_rpc/router.nim b/json_rpc/router.nim index b37c15f..fcb13b8 100644 --- a/json_rpc/router.nim +++ b/json_rpc/router.nim @@ -28,11 +28,6 @@ const paramsField = "params" jsonRpcField = "jsonrpc" idField = "id" - resultField = "result" - errorField = "error" - codeField = "code" - messageField = "message" - dataField = "data" messageTerminator = "\c\l" JSON_PARSE_ERROR* = -32700 @@ -103,7 +98,7 @@ proc checkJsonState*(line: string, proc wrapReply*(id: JsonNode, value, error: StringOfJson): StringOfJson = return StringOfJson( - """{"jsonRpcField":"2.0","idField":$1,"resultField":$2,"errorField":$3}""" % [ + """{"jsonrpc":"2.0","id":$1,"result":$2,"error":$3}""" % [ $id, string(value), string(error) ]) @@ -111,7 +106,7 @@ proc wrapError*(code: int, msg: string, id: JsonNode, data: JsonNode = newJNull()): StringOfJson {.gcsafe.} = # Create standardised error json result = StringOfJson( - """{"codeField":$1,"idField":$2,"messageField":$3,"dataField":$4}""" % [ + """{"code":$1,"id":$2,"message":$3,"data":$4}""" % [ $code, $id, escapeJson(msg), $data ]) debug "Error generated", error = result, id = id @@ -224,34 +219,28 @@ macro rpc*(server: RpcRouter, path: string, body: untyped): untyped = setup = jsonToNim(parameters, paramsIdent) procBody = if body.kind == nnkStmtList: body else: body.body - if parameters.hasReturnType: - let ReturnType = parameters[0] + let ReturnType = if parameters.hasReturnType: parameters[0] + else: ident "JsonNode" - # delegate async proc allows return and setting of result as native type - result.add quote do: - proc `doMain`(`paramsIdent`: JsonNode): Future[`ReturnType`] {.async.} = - `setup` - `procBody` + # delegate async proc allows return and setting of result as native type + result.add quote do: + proc `doMain`(`paramsIdent`: JsonNode): Future[`ReturnType`] {.async.} = + `setup` + `procBody` - if ReturnType == ident"JsonNode": - # `JsonNode` results don't need conversion - result.add quote do: - proc `procName`(`paramsIdent`: JsonNode): Future[StringOfJson] {.async, gcsafe.} = - return StringOfJson($(await `doMain`(`paramsIdent`))) - elif ReturnType == ident"StringOfJson": - result.add quote do: - proc `procName`(`paramsIdent`: JsonNode): Future[StringOfJson] {.async, gcsafe.} = - return await `doMain`(`paramsIdent`) - else: - result.add quote do: - proc `procName`(`paramsIdent`: JsonNode): Future[StringOfJson] {.async, gcsafe.} = - return StringOfJson($(%(await `doMain`(`paramsIdent`)))) - else: - # no return types, inline contents + if ReturnType == ident"JsonNode": + # `JsonNode` results don't need conversion result.add quote do: proc `procName`(`paramsIdent`: JsonNode): Future[StringOfJson] {.async, gcsafe.} = - `setup` - `procBody` + return StringOfJson($(await `doMain`(`paramsIdent`))) + elif ReturnType == ident"StringOfJson": + result.add quote do: + proc `procName`(`paramsIdent`: JsonNode): Future[StringOfJson] {.async, gcsafe.} = + return await `doMain`(`paramsIdent`) + else: + result.add quote do: + proc `procName`(`paramsIdent`: JsonNode): Future[StringOfJson] {.async, gcsafe.} = + return StringOfJson($(%(await `doMain`(`paramsIdent`)))) result.add quote do: `server`.register(`path`, `procName`) diff --git a/tests/helpers.nim b/tests/helpers.nim new file mode 100644 index 0000000..590fd33 --- /dev/null +++ b/tests/helpers.nim @@ -0,0 +1,12 @@ +import + json, ../json_rpc/router + +template `==`*(a, b: distinct (string|StringOfJson)): bool = + string(a) == string(b) + +template `==`*(a: StringOfJson, b: JsonNode): bool = + parseJson(string a) == b + +template `==`*(a: JsonNode, b: StringOfJson): bool = + a == parseJson(string b) + diff --git a/tests/testethcalls.nim b/tests/testethcalls.nim index b21ea8b..6142b3c 100644 --- a/tests/testethcalls.nim +++ b/tests/testethcalls.nim @@ -1,6 +1,7 @@ -import unittest, json, tables -import ../json_rpc/[rpcclient, rpcserver] -import stint, ethtypes, ethprocs, stintjson, chronicles +import + unittest, json, tables, + stint, ethtypes, ethprocs, stintjson, chronicles, + ../json_rpc/[rpcclient, rpcserver], ./helpers from os import getCurrentDir, DirSep from strutils import rsplit @@ -26,7 +27,7 @@ server.rpc("rpc.testreturnuint256") do() -> UInt256: let r: UInt256 = "0x1234567890abcdef".parse(UInt256, 16) return r -proc testLocalCalls: Future[seq[JsonNode]] = +proc testLocalCalls: Future[seq[StringOfJson]] = ## Call RPCs created with `rpc` locally. ## This simply demonstrates async calls of the procs generated by the `rpc` macro. var diff --git a/tests/testrpcmacro.nim b/tests/testrpcmacro.nim index 03e680a..9d29489 100644 --- a/tests/testrpcmacro.nim +++ b/tests/testrpcmacro.nim @@ -1,5 +1,5 @@ import unittest, json, chronicles, options -import ../json_rpc/rpcserver +import ../json_rpc/rpcserver, ./helpers type # some nested types to check object parsing @@ -137,7 +137,7 @@ suite "Server types": test "Simple paths": let r = waitFor rpcSimplePath(%[]) - check r == %1 + check r == "1" test "Different param types": let diff --git a/tests/testserverclient.nim b/tests/testserverclient.nim index 381a71a..2347ded 100644 --- a/tests/testserverclient.nim +++ b/tests/testserverclient.nim @@ -1,5 +1,6 @@ -import unittest, json, chronicles -import ../json_rpc/[rpcclient, rpcserver] +import + unittest, json, chronicles, + ../json_rpc/[rpcclient, rpcserver], ./helpers var srv = newRpcSocketServer(["localhost:8545"]) var client = newRpcSocketClient() @@ -19,3 +20,4 @@ suite "Server/Client RPC": srv.stop() waitFor srv.closeWait() +