src/wsabi.nim (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
import ws, asyncdispatch, asynchttpserver, strformat, asyncnet, wsabipkg/args, strutils, json, uri var server = newAsyncHttpServer() remote: WebSocket client: WebSocket clients: seq[WebSocket] proc connectRemote(host: string) {.async.} = remote = await newWebSocket(host, protocol = "xmpp") let (address, port) = remote.tcpSocket.getPeerAddr() echo fmt"connected to {address}:{port.int}" proc commRemoteClient() {.async.} = ## Fetch from remote and send to client while remote.readyState == Open: var data = await remote.receiveStrPacket() echo "from remote: ", data await client.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 = await newWebSocket(newreq, protocol = "xmpp") try: while client.readyState == Open: # TODO: don't hardcode these replacements var packet = await client.receiveStrPacket() repacket = packet.replace("127.0.0.1", by=bits.hostname) echo "from local: " & repacket await remote.send(repacket) except WebSocketError: echo "client closed socket: ", getCurrentExceptionMsg() ## 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) if hc.uri notin ["ws", "wss", "http", "https"]: let r = %*{"status": "error", "msg": &"unknown URI {hc.uri}"} await req.respond( Http400, $r, newHttpHeaders([("Content-Type", "application/json")]) ) ## 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 &"""<open xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="{hc.host}" version="1.0" />""" await ws.send(&"""<open xmlns="urn:ietf:params:xml:ns:xmpp-framing" to="{hc.host}" version="1.0" />""") echo await ws.receiveStrPacket() ws.close() let r = %*{"status": "OK"} await req.respond( Http200, $r, newHttpHeaders([("Content-Type", "application/json")]) ) except OSError as e: echo "unable to reach specified host:port pair" let r = %*{ "status": "error", "msg": e.msg } await req.respond( Http400, $r, newHttpHeaders([("Content-Type", "application/json")]) ) except KeyError as e: let r = %*{"status": "error", "msg": e.msg} await req.respond( Http400, $r, newHttpHeaders([("Content-Type", "application/json")]) ) except WebSocketError as e: let r = %*{"status": "error", "msg": e.msg} await req.respond( Http500, $r, newHttpHeaders([("Content-Type", "application/json")]) ) when isMainModule: parseArgs() echo "connecting to remote host..." waitFor connectRemote(remoteHost[0]) echo fmt"local server running at ws://127.0.0.1:{localPort}/ws" asyncCheck server.serve(Port(localPort), localServer) asyncCheck commRemoteClient() runForever() |