websocket.nim
websocket.nim copied to clipboard
Unable to elevate connection to websocket with jester
I have a simple jester webapp that uses a route as websocket. Client connecting to server throws an exception:
~/src/nim/karax-test % ./agent
/home/rk/src/nim/karax-test/agent.nim(11) agent
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(311) main
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(34) main_continue
/home/rk/src/nim/karax-test/agent.nim(6) mainIter
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1839) waitFor
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1533) poll
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1299) runOnce
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(210) processPendingCallbacks
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(34) newAsyncWebsocketClient_continue
/home/rk/src/nim/karax-test/websocket/client.nim(92) newAsyncWebsocketClientIter
[[reraised from:
/home/rk/src/nim/karax-test/agent.nim(11) agent
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(311) main
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(34) main_continue
/home/rk/src/nim/karax-test/agent.nim(6) mainIter
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1841) waitFor
/home/rk/src/nim/Nim/lib/pure/asyncfutures.nim(353) read
]]
[[reraised from:
/home/rk/src/nim/karax-test/agent.nim(11) agent
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1841) waitFor
/home/rk/src/nim/Nim/lib/pure/asyncfutures.nim(353) read
]]
Error: unhandled exception: Server did not reply with a websocket upgrade: 400 Bad Request
Async traceback:
/home/rk/src/nim/karax-test/agent.nim(11) agent
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(311) main
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(34) main_continue
/home/rk/src/nim/karax-test/agent.nim(6) mainIter
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1839) waitFor
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1533) poll
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1299) runOnce
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(210) processPendingCallbacks
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(34) newAsyncWebsocketClient_continue
/home/rk/src/nim/karax-test/websocket/client.nim(92) newAsyncWebsocketClientIter
#[
/home/rk/src/nim/karax-test/agent.nim(11) agent
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(311) main
/home/rk/src/nim/Nim/lib/pure/asyncmacro.nim(34) main_continue
/home/rk/src/nim/karax-test/agent.nim(6) mainIter
/home/rk/src/nim/Nim/lib/pure/asyncdispatch.nim(1841) waitFor
/home/rk/src/nim/Nim/lib/pure/asyncfutures.nim(353) read
]#
Exception message: Server did not reply with a websocket upgrade: 400 Bad Request
Exception type: [ProtocolError]
Server log:
INFO Jester is making jokes at http://0.0.0.0:8080
DEBUG GET
DEBUG 400 Bad Request {"content-type": @["text/html;charset=utf-8"]}
Tested version - latest master. This used to work on v0.3.5.
Server:
import asyncdispatch
import jester
import os
import strutils
import websocket
import httpcore
proc websocket_server(request: Request): Future[tuple[code: HttpCode, msg: string]] {.async.} =
var ws: tuple[ws: AsyncWebSocket, error: string]
try:
ws = await verifyWebsocketRequest(request.getNativeReq(), "app")
except:
ws.ws = nil
if ws.ws.isNil:
echo "WS negotiation failed: ", ws.error
result.code = Http400
result.msg = "Websocket negotiation failed: " & ws.error
return
while true:
var msg: tuple[opcode: Opcode, data: string]
try:
msg = await ws.ws.readData()
except:
echo getCurrentExceptionMsg()
return
try:
case msg.opcode
of Opcode.Text:
await ws.ws.sendText(msg.data)
of Opcode.Binary:
await ws.ws.sendBinary(msg.data)
of Opcode.Close:
let (closeCode, reason) = extractCloseData(msg.data)
result.code = Http200
result.msg = "Websocket closed"
return
else:
discard
except:
echo "Websocket exception: ", getCurrentExceptionMsg()
router app_router:
get "/ws":
let (code, msg) = await websocket_server(request)
resp code, msg
get "/":
resp Http200, readFile("public/index.html")
proc main() =
var port: Port
try:
port = param_str(1).parse_int().Port
except:
port = 8080.Port
let settings = new_settings(port=port)
var jester = init_jester(app_router, settings=settings)
jester.serve()
when is_main_module:
main()
Client:
import asyncdispatch
import websocket
proc main() {.async.} =
let ws: AsyncWebSocket = waitFor newAsyncWebsocketClient("localhost", Port(8080), path = "/ws", protocols = @["app"])
await ws.sendText("ping")
await ws.close()
when is_main_module:
waitFor main()