Refactoring: extract rpc handler from HTTP and WebSocket server

This commit is contained in:
jangko 2024-01-25 19:41:56 +07:00
parent dad0255c71
commit 9a34452e23
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
2 changed files with 87 additions and 66 deletions

View File

@ -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()
@ -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,

View File

@ -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)
@ -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) =