81 lines
2.7 KiB
Nim

import std/tables
import pkg/serde
import pkg/chronos/apps/http/httpclient
import pkg/chronos/apps/http/httpserver
import pkg/stew/byteutils
import pkg/questionable
export httpserver
{.push raises: [].}
type
RpcResponse* = proc(request: HttpRequestRef): Future[HttpResponseRef] {.async: (raises: [CancelledError]), raises: [].}
MockHttpServer* = object
server: HttpServerRef
rpcResponses: ref Table[string, RpcResponse]
RequestRx {.deserialize.} = object
jsonrpc*: string
id* : int
`method`* : string
proc init*(_: type MockHttpServer, address: TransportAddress): MockHttpServer =
var server: MockHttpServer
proc processRequest(r: RequestFence): Future[HttpResponseRef] {.async: (raises: [CancelledError]).} =
if r.isErr:
return defaultResponse()
let request = r.get()
try:
let body = string.fromBytes(await request.getBody())
echo "mockHttpServer.processRequest request: ", body
without req =? RequestRx.fromJson(body), error:
echo "failed to deserialize, error: ", error.msg
return await request.respond(Http400, "Invalid request, must be valid json rpc request")
echo "Received request with method: ", req.method
if not server.rpcResponses.contains(req.method):
return await request.respond(Http404, "Method not registered")
try:
let rpcResponseProc = server.rpcResponses[req.method]
return await rpcResponseProc(request)
except KeyError as e:
return await request.respond(Http500, "Method lookup error with key, error: " & e.msg)
except HttpProtocolError as e:
echo "HttpProtocolError encountered, error: ", e.msg
return defaultResponse(e)
except HttpTransportError as e:
echo "HttpTransportError encountered, error: ", e.msg
return defaultResponse(e)
except HttpWriteError as exc:
return defaultResponse(exc)
let
socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
serverFlags = {HttpServerFlags.Http11Pipeline}
res = HttpServerRef.new(address, processRequest,
socketFlags = socketFlags,
serverFlags = serverFlags)
server = MockHttpServer(server: res.get(), rpcResponses: newTable[string, RpcResponse]())
return server
template registerRpcResponse*(server: MockHttpServer, `method`: string, rpcResponse: untyped): untyped =
server.rpcResponses[`method`] = rpcResponse
proc address*(server: MockHttpServer): TransportAddress =
server.server.instance.localAddress()
proc start*(server: MockHttpServer) =
server.server.start()
proc stop*(server: MockHttpServer) {.async: (raises: []).} =
await server.server.stop()
await server.server.closeWait()