From ffc7a6378b363aed62097181deb0d6fac75df5f7 Mon Sep 17 00:00:00 2001 From: coffeepots Date: Wed, 11 Apr 2018 20:08:12 +0100 Subject: [PATCH] Make rpc transform use async --- eth-rpc/server/rpcregistration.nim | 18 ++++++++++++++---- eth-rpc/server/serverdispatch.nim | 13 ++++++------- eth-rpc/server/servertypes.nim | 2 +- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/eth-rpc/server/rpcregistration.nim b/eth-rpc/server/rpcregistration.nim index 28285f9..1f9fb6e 100644 --- a/eth-rpc/server/rpcregistration.nim +++ b/eth-rpc/server/rpcregistration.nim @@ -1,10 +1,14 @@ -import macros, servertypes +import macros, servertypes, strutils var rpcCallRefs {.compiletime.} = newSeq[(string)]() macro rpc*(prc: untyped): untyped = - # REVIEW: (IMPORTANT) I think the rpc procs should be async. - # they may need to call into other async procs of the VM + ## Converts a procedure into the following format: + ## *(params: JsonNode): Future[JsonNode] {.async.} + ## This procedure is then added into a compile-time list + ## so that it is automatically registered for every server that + ## calls registerRpcs(server) + prc.expectKind nnkProcDef result = prc let params = prc.findChild(it.kind == nnkFormalParams) @@ -20,8 +24,13 @@ macro rpc*(prc: untyped): untyped = identDefs.add ident("params"), ident("JsonNode"), newEmptyNode() # check there isn't already a result type assert params.len == 1 and params[0].kind == nnkEmpty - params[0] = ident("JsonNode") + params[0] = newNimNode(nnkBracketExpr) + params[0].add ident("Future"), ident("JsonNode") params.add identDefs + # add async pragma, we can assume there isn't an existing .async. + # as this would fail the result check above. + prc.addPragma(newIdentNode("async")) + # Adds to compiletime list of rpc calls so we can register them in bulk # for multiple servers using `registerRpcs`. rpcCallRefs.add $procName @@ -33,3 +42,4 @@ macro registerRpcs*(server: RpcServer): untyped = for procName in rpcCallRefs: let de = newDotExpr(ident($server), ident("register")) result.add(newCall(de, newStrLitNode(procName), ident(procName))) + echo result.repr diff --git a/eth-rpc/server/serverdispatch.nim b/eth-rpc/server/serverdispatch.nim index 020fd30..54ce450 100644 --- a/eth-rpc/server/serverdispatch.nim +++ b/eth-rpc/server/serverdispatch.nim @@ -20,7 +20,7 @@ proc processMessage(server: RpcServer, client: AsyncSocket, line: string) {.asyn if not server.procs.hasKey(methodName): await client.sendError(METHOD_NOT_FOUND, "Method not found", id, %(methodName & " is not a registered method.")) else: - let callRes = server.procs[methodName](node["params"]) + let callRes = await server.procs[methodName](node["params"]) await client.send($wrapReply(id, callRes, newJNull()) & "\c\l") proc processClient(server: RpcServer, client: AsyncSocket) {.async.} = @@ -33,12 +33,11 @@ proc processClient(server: RpcServer, client: AsyncSocket) {.async.} = ifDebug: echo "Process client: ", server.port, ":" & line - let fut = processMessage(server, client, line) - await fut - if fut.failed: - if fut.readError of RpcProcError: - # TODO: Currently exceptions in rpc calls are not properly handled - let err = fut.readError.RpcProcError + let future = processMessage(server, client, line) + await future + if future.failed: + if future.readError of RpcProcError: + let err = future.readError.RpcProcError await client.sendError(err.code, err.msg, err.data) else: await client.sendError(-32000, "Error", %getCurrentExceptionMsg()) diff --git a/eth-rpc/server/servertypes.nim b/eth-rpc/server/servertypes.nim index 1fc1954..61ee711 100644 --- a/eth-rpc/server/servertypes.nim +++ b/eth-rpc/server/servertypes.nim @@ -1,7 +1,7 @@ import asyncdispatch, asyncnet, json, tables type - RpcProc* = proc (params: JsonNode): JsonNode + RpcProc* = proc (params: JsonNode): Future[JsonNode] RpcServer* = ref object socket*: AsyncSocket