107 lines
3.4 KiB
Nim

{.push raises: [Defect].}
import
pkg/websock/websock,
./servers/[httpserver],
./clients/[httpclient, websocketclient]
type
ClientKind* = enum
Http,
WebSocket
ClientConfig* = object
case kind*: ClientKind
of Http:
httpUri*: string
of WebSocket:
wsUri*: string
compression*: bool
flags*: set[TLSFlags]
RpcProxy* = ref object of RootRef
rpcHttpServer*: RpcHttpServer
case kind*: ClientKind
of Http:
httpUri*: string
httpClient*: RpcHttpClient
of WebSocket:
wsUri*: string
webSocketClient*: RpcWebSocketClient
compression*: bool
flags*: set[TLSFlags]
# TODO Add validations that provided uri-s are correct https/wss uri and retrun
# Result[string, ClientConfig]
proc getHttpClientConfig*(uri: string): ClientConfig =
ClientConfig(kind: Http, httpUri: uri)
proc getWebSocketClientConfig*(
uri: string,
compression: bool = false,
flags: set[TLSFlags] = {
NoVerifyHost, NoVerifyServerName}): ClientConfig =
ClientConfig(kind: WebSocket, wsUri: uri, compression: compression, flags: flags)
proc proxyCall(client: RpcClient, name: string): RpcProc =
return proc (params: JsonNode): Future[StringOfJson] {.async.} =
let res = await client.call(name, params)
return StringOfJson($res)
proc getClient(proxy: RpcProxy): RpcClient =
case proxy.kind
of Http:
proxy.httpClient
of WebSocket:
proxy.webSocketClient
proc new*(T: type RpcProxy, server: RpcHttpServer, cfg: ClientConfig): T =
case cfg.kind
of Http:
let client = newRpcHttpClient()
return T(rpcHttpServer: server, kind: Http, httpUri: cfg.httpUri, httpClient: client)
of WebSocket:
let client = newRpcWebSocketClient()
return T(
rpcHttpServer: server,
kind: WebSocket,
wsUri: cfg.wsUri,
webSocketClient: client,
compression: cfg.compression,
flags: cfg.flags
)
proc new*(T: type RpcProxy, listenAddresses: openArray[TransportAddress], cfg: ClientConfig): T {.raises: [Defect, CatchableError].} =
RpcProxy.new(newRpcHttpServer(listenAddresses, RpcRouter.init()), cfg)
proc new*(T: type RpcProxy, listenAddresses: openArray[string], cfg: ClientConfig): T {.raises: [Defect, CatchableError].} =
RpcProxy.new(newRpcHttpServer(listenAddresses, RpcRouter.init()), cfg)
proc connectToProxy(proxy: RpcProxy): Future[void] =
case proxy.kind
of Http:
return proxy.httpClient.connect(proxy.httpUri)
of WebSocket:
return proxy.webSocketClient.connect(proxy.wsUri, proxy.compression, proxy.flags)
proc start*(proxy: RpcProxy) {.async.} =
proxy.rpcHttpServer.start()
await proxy.connectToProxy()
template rpc*(server: RpcProxy, path: string, body: untyped): untyped =
server.rpcHttpServer.rpc(path, body)
proc registerProxyMethod*(proxy: var RpcProxy, methodName: string) =
try:
proxy.rpcHttpServer.register(methodName, proxyCall(proxy.getClient(), methodName))
except CatchableError as err:
# Adding proc type to table gives invalid exception tracking, see Nim bug: https://github.com/nim-lang/Nim/issues/18376
raiseAssert err.msg
proc stop*(proxy: RpcProxy) {.async.} =
await proxy.getClient().close()
await proxy.rpcHttpServer.stop()
proc closeWait*(proxy: RpcProxy) {.async.} =
await proxy.rpcHttpServer.closeWait()