Skip to content

Commit

Permalink
Refactoring: extract rpc handler from HTTP and WebSocket server
Browse files Browse the repository at this point in the history
  • Loading branch information
jangko committed Jan 25, 2024
1 parent dad0255 commit 9a34452
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 66 deletions.
96 changes: 54 additions & 42 deletions json_rpc/servers/httpserver.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,63 @@ type
HttpAuthHook* = proc(request: HttpRequestRef): Future[HttpResponseRef]
{.gcsafe, raises: [Defect, CatchableError].}

RpcHttpServer* = ref object of RpcServer
# This inheritance arrangement is useful for
# e.g. combo HTTP server
RpcHttpHandler* = ref object of RpcServer
maxChunkSize*: int

RpcHttpServer* = ref object of RpcHttpHandler
httpServers: seq[HttpServerRef]
authHooks: seq[HttpAuthHook]
maxChunkSize: int

proc serveHTTP*(rpcServer: RpcHttpHandler, request: HttpRequestRef):
Future[HttpResponseRef] {.async: (raises: [CancelledError]).} =
let
headers = HttpTable.init([("Content-Type",
"application/json; charset=utf-8")])
chunkSize = rpcServer.maxChunkSize

try:
let
body = await request.getBody()
data = await rpcServer.route(string.fromBytes(body))

if data.len <= chunkSize:
let res = await request.respond(Http200, data, headers)
trace "JSON-RPC result has been sent"
return res

let response = request.getResponse()
response.status = Http200
response.addHeader("Content-Type", "application/json; charset=utf-8")

await response.prepare()
let maxLen = data.len

var len = data.len
while len > chunkSize:
await response.sendChunk(data[maxLen - len].unsafeAddr, chunkSize)
len -= chunkSize

if len > 0:
await response.sendChunk(data[maxLen - len].unsafeAddr, len)

await response.finish()
except CancelledError as exc:
raise exc
except CatchableError as exc:
debug "Internal error while processing JSON-RPC call"
try:
return await request.respond(
Http503,
"Internal error while processing JSON-RPC call: " & exc.msg)
except HttpWriteError as exc:
error "Something error", msg=exc.msg
return defaultResponse()

proc processClientRpc(rpcServer: RpcHttpServer): HttpProcessCallback2 =
return proc (req: RequestFence): Future[HttpResponseRef] {.async: (raises: [CancelledError]).} =
return proc (req: RequestFence): Future[HttpResponseRef]
{.async: (raises: [CancelledError]).} =
if not req.isOk():
return defaultResponse()

Expand All @@ -62,45 +112,7 @@ proc processClientRpc(rpcServer: RpcHttpServer): HttpProcessCallback2 =
error "Something error", msg=exc.msg
return defaultResponse()

let
headers = HttpTable.init([("Content-Type",
"application/json; charset=utf-8")])
chunkSize = rpcServer.maxChunkSize

try:
let
body = await request.getBody()
data = await rpcServer.route(string.fromBytes(body))

if data.len <= chunkSize:
let res = await request.respond(Http200, data, headers)
trace "JSON-RPC result has been sent"
return res

let response = request.getResponse()
response.status = Http200
response.addHeader("Content-Type", "application/json; charset=utf-8")
await response.prepare()
let maxLen = data.len
var len = data.len
while len > chunkSize:
await response.sendChunk(data[maxLen - len].unsafeAddr, chunkSize)
len -= chunkSize
if len > 0:
await response.sendChunk(data[maxLen - len].unsafeAddr, len)
await response.finish()

except CancelledError as exc:
raise exc
except CatchableError as exc:
debug "Internal error while processing JSON-RPC call"
try:
return await request.respond(
Http503,
"Internal error while processing JSON-RPC call: " & exc.msg)
except HttpWriteError as exc:
error "Something error", msg=exc.msg
return defaultResponse()
return await rpcServer.serveHTTP(request)

proc addHttpServer*(
rpcServer: RpcHttpServer,
Expand Down
57 changes: 33 additions & 24 deletions json_rpc/servers/websocketserver.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,17 @@ type
WsAuthHook* = proc(request: HttpRequest): Future[bool]
{.gcsafe, raises: [Defect, CatchableError].}

RpcWebSocketServer* = ref object of RpcServer
# This inheritance arrangement is useful for
# e.g. combo HTTP server
RpcWebSocketHandler* = ref object of RpcServer
wsserver*: WSServer

RpcWebSocketServer* = ref object of RpcWebSocketHandler
server: StreamServer
wsserver: WSServer
authHooks: seq[WsAuthHook]

proc handleRequest(rpc: RpcWebSocketServer, request: HttpRequest) {.async: (raises: [CancelledError]).} =
trace "Handling request:", uri = request.uri.path
trace "Initiating web socket connection."

# if hook result is false,
# it means we should return immediately
try:
for hook in rpc.authHooks:
let res = await hook(request)
if not res:
return
except CatchableError as exc:
error "Internal error while processing JSON-RPC hook", msg=exc.msg
try:
await request.sendResponse(Http503,
data = "",
content = "Internal error, processing JSON-RPC hook: " & exc.msg)
return
except CatchableError as exc:
error "Something error", msg=exc.msg
return

proc serveHTTP*(rpc: RpcWebSocketHandler, request: HttpRequest)
{.async: (raises: [CancelledError]).} =
try:
let server = rpc.wsserver
let ws = await server.handleRequest(request)
Expand Down Expand Up @@ -99,6 +83,31 @@ proc handleRequest(rpc: RpcWebSocketServer, request: HttpRequest) {.async: (rais
except CatchableError as exc:
error "Something error", msg=exc.msg

proc handleRequest(rpc: RpcWebSocketServer, request: HttpRequest)
{.async: (raises: [CancelledError]).} =
trace "Handling request:", uri = request.uri.path
trace "Initiating web socket connection."

# if hook result is false,
# it means we should return immediately
try:
for hook in rpc.authHooks:
let res = await hook(request)
if not res:
return
except CatchableError as exc:
error "Internal error while processing JSON-RPC hook", msg=exc.msg
try:
await request.sendResponse(Http503,
data = "",
content = "Internal error, processing JSON-RPC hook: " & exc.msg)
return
except CatchableError as exc:
error "Something error", msg=exc.msg
return

await rpc.serveHTTP(request)

proc initWebsocket(rpc: RpcWebSocketServer, compression: bool,
authHooks: seq[WsAuthHook],
rng: ref HmacDrbgContext) =
Expand Down

0 comments on commit 9a34452

Please sign in to comment.