Prototype 'on' transformation - work in progress

This commit is contained in:
coffeepots 2018-04-20 21:19:08 +01:00
parent a02934d1e2
commit 961702e8e2
1 changed files with 70 additions and 23 deletions

View File

@ -13,8 +13,6 @@ type
code*: int
data*: JsonNode
var rpcCallRefs {.compiletime.} = newSeq[(string)]()
proc register*(server: RpcServer, name: string, rpc: RpcProc) =
server.procs[name] = rpc
@ -52,30 +50,79 @@ macro rpc*(prc: untyped): untyped =
# as this would mean there's a return type and 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
macro registerRpcs*(server: RpcServer): untyped =
## Step through procs currently registered with {.rpc.} and add a register call for this server
result = newStmtList()
result.add(quote do:
`server`.unRegisterAll
)
for procName in rpcCallRefs:
let i = ident(procName)
result.add(quote do:
`server`.register(`procName`, `i`)
)
include ethprocs # TODO: This isn't ideal as it means editing code in ethprocs shows errors
proc newRpcServer*(address: string, port: Port = Port(8545)): RpcServer =
proc newRpcServer*(address = "localhost", port: Port = Port(8545)): RpcServer =
result = RpcServer(
socket: newAsyncSocket(),
port: port,
address: address,
procs: newTable[string, RpcProc]()
)
result.registerRpcs
var sharedServer: RpcServer
proc sharedRpcServer*(): RpcServer =
if sharedServer.isNil: sharedServer = newRpcServer("")
result = sharedServer
macro multiRemove(s: string, values: varargs[string]): untyped =
## wrapper for multiReplace
result = newStmtList()
var call = newNimNode(nnkCall)
call.add(ident"multiReplace")
call.add(s)
for item in values:
let sItem = $item
# generate tuples with empty strings
call.add(newPar(newStrLitNode(sItem), newStrLitNode("")))
result.add call
macro on*(server: var RpcServer, path: string, body: untyped): untyped =
var paramTemplates = newStmtList()
# process parameters of body into templates
let parameters = body.findChild(it.kind == nnkFormalParams)
if not parameters.isNil:
# marshall result to json
var resType = parameters[0]
if resType.kind != nnkEmpty:
# TODO: transform result type and/or return to json
discard
# convert input parameters to json fetch templates
for i in 1..<parameters.len:
parameters[i].expectKind nnkIdentDefs
let
name = parameters[i][0]
nameStr = $name
paramType = parameters[i][1]
paramTemplates.add(quote do:
template `name`: `paramType` = params[`nameStr`]
)
# create RPC proc
let
pathStr = $path
procName = ident(pathStr.multiRemove(".", "/"))
paramsIdent = ident("params")
var
procBody: NimNode
if body.kind == nnkStmtList: procBody = body
else: procBody = body.body
result = quote do:
proc `procName`*(`paramsIdent`: JsonNode): Future[JsonNode] {.async.} =
`paramTemplates`
`procBody`
`server`.register(`path`, `procName`)
echo result.repr
when isMainModule:
import asyncdispatch, asyncnet
var s = newRpcServer("localhost")
s.on("the/path") do(a: int, b: string):
var node = %"test"
await node
s.on("the/path2") do() -> int:
echo "hello2"
s.on("the/path3"):
echo "hello3"
assert s.procs.hasKey("the/path")
assert s.procs.hasKey("the/path2")
assert s.procs.hasKey("the/path3")