mirror of
https://github.com/status-im/nim-json-rpc.git
synced 2025-02-25 02:35:15 +00:00
Eliminate code duplication in the HTTP/S servers
This commit is contained in:
parent
e4dba96f5c
commit
c455198d4f
@ -117,4 +117,3 @@ proc connect*(client: RpcHttpClient, address: string, port: Port, secure: bool)
|
||||
client.httpAddress = res
|
||||
else:
|
||||
raise newException(RpcAddressUnresolvableError, res.error)
|
||||
|
||||
|
@ -2,7 +2,7 @@ import
|
||||
stew/byteutils,
|
||||
std/[strutils],
|
||||
chronicles, httputils, chronos,
|
||||
chronos/apps/http/httpserver,
|
||||
chronos/apps/http/[httpserver, shttpserver],
|
||||
".."/[errors, server]
|
||||
|
||||
export server
|
||||
@ -17,33 +17,58 @@ type
|
||||
RpcHttpServer* = ref object of RpcServer
|
||||
httpServers: seq[HttpServerRef]
|
||||
|
||||
proc addHttpServer*(rpcServer: RpcHttpServer, address: TransportAddress) =
|
||||
proc processClientRpc(rpcServer: RpcHttpServer): HttpProcessCallback {.closure.} =
|
||||
return proc (req: RequestFence): Future[HttpResponseRef] {.async.} =
|
||||
if req.isOk():
|
||||
let request = req.get()
|
||||
let body = await request.getBody()
|
||||
proc processClientRpc(rpcServer: RpcServer): HttpProcessCallback =
|
||||
return proc (req: RequestFence): Future[HttpResponseRef] {.async.} =
|
||||
if req.isOk():
|
||||
let request = req.get()
|
||||
let body = await request.getBody()
|
||||
|
||||
let future = rpcServer.route(string.fromBytes(body))
|
||||
yield future
|
||||
if future.failed:
|
||||
debug "Internal error while processing JSON-RPC call"
|
||||
return await request.respond(Http503, "Internal error while processing JSON-RPC call")
|
||||
else:
|
||||
var data = future.read()
|
||||
let res = await request.respond(Http200, data)
|
||||
trace "JSON-RPC result has been sent"
|
||||
return res
|
||||
let future = rpcServer.route(string.fromBytes(body))
|
||||
yield future
|
||||
if future.failed:
|
||||
debug "Internal error while processing JSON-RPC call"
|
||||
return await request.respond(Http503, "Internal error while processing JSON-RPC call")
|
||||
else:
|
||||
return dumbResponse()
|
||||
var data = future.read()
|
||||
let res = await request.respond(Http200, data)
|
||||
trace "JSON-RPC result has been sent"
|
||||
return res
|
||||
else:
|
||||
return dumbResponse()
|
||||
|
||||
proc addHttpServer*(rpcServer: RpcHttpServer, address: TransportAddress) =
|
||||
let initialServerCount = len(rpcServer.httpServers)
|
||||
try:
|
||||
info "Starting JSON-RPC HTTP server", url = "http://" & $address
|
||||
var res = HttpServerRef.new(address, processClientRpc(rpcServer))
|
||||
if res.isOk():
|
||||
let httpServer = res.get()
|
||||
rpcServer.httpServers.add(httpServer)
|
||||
rpcServer.httpServers.add(res.get())
|
||||
else:
|
||||
raise newException(RpcBindError, "Unable to create server!")
|
||||
|
||||
except CatchableError as exc:
|
||||
error "Failed to create server", address = $address,
|
||||
message = exc.msg
|
||||
|
||||
if len(rpcServer.httpServers) != initialServerCount + 1:
|
||||
# Server was not bound, critical error.
|
||||
raise newException(RpcBindError, "Unable to create server!")
|
||||
|
||||
proc addSecureHttpServer*(rpcServer: RpcHttpServer,
|
||||
address: TransportAddress,
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate) =
|
||||
let initialServerCount = len(rpcServer.httpServers)
|
||||
try:
|
||||
info "Starting JSON-RPC HTTPS server", url = "https://" & $address
|
||||
var res = SecureHttpServerRef.new(address,
|
||||
processClientRpc(rpcServer),
|
||||
tlsPrivateKey,
|
||||
tlsCertificate,
|
||||
serverFlags = {HttpServerFlags.Secure},
|
||||
socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr})
|
||||
if res.isOk():
|
||||
rpcServer.httpServers.add(res.get())
|
||||
else:
|
||||
raise newException(RpcBindError, "Unable to create server!")
|
||||
|
||||
@ -60,8 +85,26 @@ proc addHttpServers*(server: RpcHttpServer,
|
||||
for item in addresses:
|
||||
server.addHttpServer(item)
|
||||
|
||||
proc addHttpServer*(server: RpcHttpServer, address: string) =
|
||||
## Create new server and assign it to addresses ``addresses``.
|
||||
proc addSecureHttpServers*(server: RpcHttpServer,
|
||||
addresses: openArray[TransportAddress],
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate) =
|
||||
for item in addresses:
|
||||
server.addSecureHttpServer(item, tlsPrivateKey, tlsCertificate)
|
||||
|
||||
template processResolvedAddresses =
|
||||
if tas4.len + tas6.len == 0:
|
||||
# Addresses could not be resolved, critical error.
|
||||
raise newException(RpcAddressUnresolvableError, "Unable to get address!")
|
||||
|
||||
for r in tas4:
|
||||
yield r
|
||||
|
||||
if tas4.len == 0: # avoid ipv4 + ipv6 running together
|
||||
for r in tas6:
|
||||
yield r
|
||||
|
||||
iterator resolvedAddresses(address: string): TransportAddress =
|
||||
var
|
||||
tas4: seq[TransportAddress]
|
||||
tas6: seq[TransportAddress]
|
||||
@ -79,23 +122,9 @@ proc addHttpServer*(server: RpcHttpServer, address: string) =
|
||||
except CatchableError:
|
||||
discard
|
||||
|
||||
for r in tas4:
|
||||
server.addHttpServer(r)
|
||||
added.inc
|
||||
if added == 0: # avoid ipv4 + ipv6 running together
|
||||
for r in tas6:
|
||||
server.addHttpServer(r)
|
||||
added.inc
|
||||
processResolvedAddresses()
|
||||
|
||||
if added == 0:
|
||||
# Addresses could not be resolved, critical error.
|
||||
raise newException(RpcAddressUnresolvableError, "Unable to get address!")
|
||||
|
||||
proc addHttpServers*(server: RpcHttpServer, addresses: openArray[string]) =
|
||||
for address in addresses:
|
||||
server.addHttpServer(address)
|
||||
|
||||
proc addHttpServer*(server: RpcHttpServer, address: string, port: Port) =
|
||||
iterator resolvedAddresses(address: string, port: Port): TransportAddress =
|
||||
var
|
||||
tas4: seq[TransportAddress]
|
||||
tas6: seq[TransportAddress]
|
||||
@ -113,23 +142,41 @@ proc addHttpServer*(server: RpcHttpServer, address: string, port: Port) =
|
||||
except CatchableError:
|
||||
discard
|
||||
|
||||
if len(tas4) == 0 and len(tas6) == 0:
|
||||
# Address was not resolved, critical error.
|
||||
raise newException(RpcAddressUnresolvableError,
|
||||
"Address " & address & " could not be resolved!")
|
||||
processResolvedAddresses()
|
||||
|
||||
for r in tas4:
|
||||
server.addHttpServer(r)
|
||||
added.inc
|
||||
for r in tas6:
|
||||
server.addHttpServer(r)
|
||||
added.inc
|
||||
proc addHttpServer*(server: RpcHttpServer, address: string) =
|
||||
## Create new server and assign it to addresses ``addresses``.
|
||||
for a in resolvedAddresses(address):
|
||||
server.addHttpServer(a)
|
||||
|
||||
proc addSecureHttpServer*(server: RpcHttpServer,
|
||||
address: string,
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate) =
|
||||
for a in resolvedAddresses(address):
|
||||
server.addSecureHttpServer(a, tlsPrivateKey, tlsCertificate)
|
||||
|
||||
proc addHttpServers*(server: RpcHttpServer, addresses: openArray[string]) =
|
||||
for address in addresses:
|
||||
server.addHttpServer(address)
|
||||
|
||||
proc addHttpServer*(server: RpcHttpServer, address: string, port: Port) =
|
||||
for a in resolvedAddresses(address, port):
|
||||
server.addHttpServer(a)
|
||||
|
||||
if len(server.httpServers) == 0:
|
||||
# Server was not bound, critical error.
|
||||
raise newException(RpcBindError,
|
||||
"Could not setup server on " & address & ":" & $int(port))
|
||||
|
||||
proc addSecureHttpServer*(server: RpcHttpServer,
|
||||
address: string,
|
||||
port: Port,
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate) =
|
||||
for a in resolvedAddresses(address, port):
|
||||
server.addSecureHttpServer(a, tlsPrivateKey, tlsCertificate)
|
||||
|
||||
proc new*(T: type RpcHttpServer): T =
|
||||
T(router: RpcRouter.init(), httpServers: @[])
|
||||
|
||||
|
@ -1,198 +0,0 @@
|
||||
import
|
||||
stew/byteutils,
|
||||
std/[strutils],
|
||||
chronicles, httputils, chronos,
|
||||
chronos/apps/http/shttpserver,
|
||||
".."/[errors, server]
|
||||
|
||||
export server
|
||||
|
||||
logScope:
|
||||
topics = "JSONRPC-HTTPS-SERVER"
|
||||
|
||||
type
|
||||
ReqStatus = enum
|
||||
Success, Error, ErrorFailure
|
||||
|
||||
RpcSecureHttpServer* = ref object of RpcServer
|
||||
secureHttpServers: seq[SecureHttpServerRef]
|
||||
|
||||
proc addSecureHttpServer*(rpcServer: RpcSecureHttpServer,
|
||||
address: TransportAddress,
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate
|
||||
) =
|
||||
proc processClientRpc(rpcServer: RpcSecureHttpServer): HttpProcessCallback {.closure.} =
|
||||
return proc (req: RequestFence): Future[HttpResponseRef] {.async.} =
|
||||
if req.isOk():
|
||||
let request = req.get()
|
||||
let body = await request.getBody()
|
||||
|
||||
let future = rpcServer.route(string.fromBytes(body))
|
||||
yield future
|
||||
if future.failed:
|
||||
debug "Internal error while processing JSON-RPC call"
|
||||
return await request.respond(Http503, "Internal error while processing JSON-RPC call")
|
||||
else:
|
||||
var data = future.read()
|
||||
let res = await request.respond(Http200, data)
|
||||
trace "JSON-RPC result has been sent"
|
||||
return res
|
||||
else:
|
||||
if req.error.code == Http408:
|
||||
debug "Timeout error while processing JSON-RPC call"
|
||||
return dumbResponse()
|
||||
|
||||
let initialServerCount = len(rpcServer.secureHttpServers)
|
||||
try:
|
||||
info "Starting JSON-RPC HTTPS server", url = "https://" & $address
|
||||
var res = SecureHttpServerRef.new(address,
|
||||
processClientRpc(rpcServer),
|
||||
tlsPrivateKey,
|
||||
tlsCertificate,
|
||||
serverFlags = {Secure},
|
||||
socketFlags = {ServerFlags.TcpNoDelay, ServerFlags.ReuseAddr}
|
||||
)
|
||||
if res.isOk():
|
||||
let secureHttpServer = res.get()
|
||||
rpcServer.secureHttpServers.add(secureHttpServer)
|
||||
else:
|
||||
raise newException(RpcBindError, "Unable to create server!")
|
||||
|
||||
except CatchableError as exc:
|
||||
error "Failed to create server", address = $address,
|
||||
message = exc.msg
|
||||
|
||||
if len(rpcServer.secureHttpServers) != initialServerCount + 1:
|
||||
# Server was not bound, critical error.
|
||||
raise newException(RpcBindError, "Unable to create server!")
|
||||
|
||||
proc addSecureHttpServers*(server: RpcSecureHttpServer,
|
||||
addresses: openArray[TransportAddress],
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate
|
||||
) =
|
||||
for item in addresses:
|
||||
server.addSecureHttpServer(item, tlsPrivateKey, tlsCertificate)
|
||||
|
||||
proc addSecureHttpServer*(server: RpcSecureHttpServer,
|
||||
address: string,
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate
|
||||
) =
|
||||
## Create new server and assign it to addresses ``addresses``.
|
||||
var
|
||||
tas4: seq[TransportAddress]
|
||||
tas6: seq[TransportAddress]
|
||||
added = 0
|
||||
|
||||
# Attempt to resolve `address` for IPv4 address space.
|
||||
try:
|
||||
tas4 = resolveTAddress(address, AddressFamily.IPv4)
|
||||
except CatchableError:
|
||||
discard
|
||||
|
||||
# Attempt to resolve `address` for IPv6 address space.
|
||||
try:
|
||||
tas6 = resolveTAddress(address, AddressFamily.IPv6)
|
||||
except CatchableError:
|
||||
discard
|
||||
|
||||
for r in tas4:
|
||||
server.addSecureHttpServer(r, tlsPrivateKey, tlsCertificate)
|
||||
added.inc
|
||||
if added == 0: # avoid ipv4 + ipv6 running together
|
||||
for r in tas6:
|
||||
server.addSecureHttpServer(r, tlsPrivateKey, tlsCertificate)
|
||||
added.inc
|
||||
|
||||
if added == 0:
|
||||
# Addresses could not be resolved, critical error.
|
||||
raise newException(RpcAddressUnresolvableError, "Unable to get address!")
|
||||
|
||||
proc addSecureHttpServers*(server: RpcSecureHttpServer,
|
||||
addresses: openArray[string],
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate
|
||||
) =
|
||||
for address in addresses:
|
||||
server.addSecureHttpServer(address, tlsPrivateKey, tlsCertificate)
|
||||
|
||||
proc addSecureHttpServer*(server: RpcSecureHttpServer,
|
||||
address: string,
|
||||
port: Port,
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate
|
||||
) =
|
||||
var
|
||||
tas4: seq[TransportAddress]
|
||||
tas6: seq[TransportAddress]
|
||||
added = 0
|
||||
|
||||
# Attempt to resolve `address` for IPv4 address space.
|
||||
try:
|
||||
tas4 = resolveTAddress(address, port, AddressFamily.IPv4)
|
||||
except CatchableError:
|
||||
discard
|
||||
|
||||
# Attempt to resolve `address` for IPv6 address space.
|
||||
try:
|
||||
tas6 = resolveTAddress(address, port, AddressFamily.IPv6)
|
||||
except CatchableError:
|
||||
discard
|
||||
|
||||
if len(tas4) == 0 and len(tas6) == 0:
|
||||
# Address was not resolved, critical error.
|
||||
raise newException(RpcAddressUnresolvableError,
|
||||
"Address " & address & " could not be resolved!")
|
||||
|
||||
for r in tas4:
|
||||
server.addSecureHttpServer(r, tlsPrivateKey, tlsCertificate)
|
||||
added.inc
|
||||
for r in tas6:
|
||||
server.addSecureHttpServer(r, tlsPrivateKey, tlsCertificate)
|
||||
added.inc
|
||||
|
||||
if len(server.secureHttpServers) == 0:
|
||||
# Server was not bound, critical error.
|
||||
raise newException(RpcBindError,
|
||||
"Could not setup server on " & address & ":" & $int(port))
|
||||
|
||||
proc new*(T: type RpcSecureHttpServer): T =
|
||||
T(router: RpcRouter.init(), secureHttpServers: @[])
|
||||
|
||||
proc newRpcSecureHttpServer*(): RpcSecureHttpServer =
|
||||
RpcSecureHttpServer.new()
|
||||
|
||||
proc newRpcSecureHttpServer*(addresses: openArray[TransportAddress],
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate
|
||||
): RpcSecureHttpServer =
|
||||
## Create new server and assign it to addresses ``addresses``.
|
||||
result = newRpcSecureHttpServer()
|
||||
result.addSecureHttpServers(addresses, tlsPrivateKey, tlsCertificate)
|
||||
|
||||
proc newRpcSecureHttpServer*(addresses: openArray[string],
|
||||
tlsPrivateKey: TLSPrivateKey,
|
||||
tlsCertificate: TLSCertificate
|
||||
): RpcSecureHttpServer =
|
||||
## Create new server and assign it to addresses ``addresses``.
|
||||
result = newRpcSecureHttpServer()
|
||||
result.addSecureHttpServers(addresses, tlsPrivateKey, tlsCertificate)
|
||||
|
||||
proc start*(server: RpcSecureHttpServer) =
|
||||
## Start the RPC server.
|
||||
for item in server.secureHttpServers:
|
||||
debug "HTTPS RPC server started" # (todo: fix this), address = item
|
||||
item.start()
|
||||
|
||||
proc stop*(server: RpcSecureHttpServer) {.async.} =
|
||||
## Stop the RPC server.
|
||||
for item in server.secureHttpServers:
|
||||
debug "HTTPS RPC server stopped" # (todo: fix this), address = item.local
|
||||
await item.stop()
|
||||
|
||||
proc closeWait*(server: RpcSecureHttpServer) {.async.} =
|
||||
## Cleanup resources of RPC server.
|
||||
for item in server.secureHttpServers:
|
||||
await item.closeWait()
|
Loading…
x
Reference in New Issue
Block a user