import
ws,
asyncdispatch,
asynchttpserver,
strformat,
asyncnet,
wsabipkg/[args,httputils],
httpclient,
strutils,
json,
uri
type
Client = object
ws: WebSocket
remote: WebSocket
var
server = newAsyncHttpServer()
client: Client
clients = newSeq[Client]()
proc commRemoteClient(c: Client) {.async.} =
## Fetch from remote and send to client
while c.remote.readyState == Open:
var data = await c.remote.receiveStrPacket()
echo "from remote: ", data
await c.ws.send(data)
proc localServer(req: Request) {.async, gcsafe.} =
## Listen on localhost:PORT/ws
if req.url.path == "/ws":
var newreq = req
# TODO: loop through for all remote hosts
let bits = parseUri(remoteHost[0])
newreq.headers["host"] = @[fmt"{bits.hostname}:{bits.port}"]
newreq.headers["hostname"] = @[bits.hostname]
client.ws = await newWebSocket(newreq, protocol = "xmpp")
echo "connecting to remote host..."
client.remote = await newWebSocket(remoteHost[0], protocol = "xmpp")
let (address, port) = client.remote.tcpSocket.getPeerAddr()
echo fmt"connected to {address}:{port.int}"
clients.add client
try:
while client.ws.readyState == Open:
let clientAddress = client.ws.tcpSocket.getPeerAddr()[0]
var
packet = await client.ws.receiveStrPacket()
repacket = packet.replace(clientAddress, by=bits.hostname)
echo "from local: " & repacket
await client.remote.send(repacket)
echo "sent local packet"
asyncCheck commRemoteClient(client)
except WebSocketError as e:
echo "client closed socket: ", e.msg
## Health check endpoint
## The 'uri' can be either 'ws' or 'http'.
if req.url.path == "/check-health":
if req.reqMethod == HttpPost:
type
HealthCheck = object
uri: string
host: string
port: int
try:
let
hcJson = parseJson(req.body)
hc = to(hcJson, HealthCheck)
## Check if host is a websocket, and try for the xmpp protocol
if hc.uri in ["ws", "wss"]:
let hostStr = &"{hc.uri}://{hc.host}:{hc.port}/ws/"
echo &"connecting to {hostStr}"
var ws = await newWebSocket(hostStr, protocol = "xmpp")
echo "sending test packet"
echo &""""""
await ws.send(&"""""")
echo await ws.receiveStrPacket()
ws.close()
let r = %*{"status": "OK"}
await req.makeResponse(Http200, $r)
if hc.uri in ["http", "https"]:
let hostStr = &"{hc.uri}://{hc.host}:{hc.port}/"
echo &"connecting to {hostStr}"
var tmpClient = newAsyncHttpClient()
echo await tmpClient.getContent(hostStr)
let r = %*{"status": "OK"}
await req.makeResponse(Http200, $r)
else:
let r = %*{"status": "error", "msg": &"unknown URI {hc.uri}"}
await req.makeResponse(Http400, $r)
except OSError as e:
echo "unable to reach specified host:port pair"
let r = %*{
"status": "error",
"msg": e.msg
}
await req.makeResponse(Http400, $r)
except KeyError as e:
let r = %*{"status": "error", "msg": e.msg}
await req.makeResponse(Http400, $r)
except WebSocketError as e:
let r = %*{"status": "error", "msg": e.msg}
await req.makeResponse(Http500, $r)
when isMainModule:
parseArgs()
echo fmt"local server running at ws://127.0.0.1:{localPort}/ws"
asyncCheck server.serve(Port(localPort), localServer)
runForever()