I see two options: https://github.com/treeform/ws https://github.com/status-im/nim-websock
While nim-websock is more actively developed, there's no Nimble package or tag/release available. Can anyone recommend one or the other, or perhaps a 3rd option?
Thanks. I'll take a look.
I just realized what I really want is a websocket library that isn't async. This is because I'm using threads, and mixing the two seems troublesome.
websocket.nim which I used first started giving weird errors with packets merging into each other and SSL failing. Then I switched to ws, but didn't want to change my code too much, so I just made a wrapper over both.
import ../common # defines websocketBackend
when websocketBackend == "ws":
import pkg/ws as pkgws
export pkgws
template isClosed*(ws: WebSocket): bool =
ws.readyState == ReadyState.Closed
template readData*(ws: WebSocket): untyped =
ws.receivePacket
proc extractCloseData*(data: string): tuple[code: int, reason: string] =
## A way to get the close code and reason out of the data of a Close opcode.
var data = data
result.code =
if data.len >= 2:
(data[0].int shl 8) or data[1].int
else:
0
result.reason = if data.len > 2: data[2..^1] else: ""
elif websocketBackend == "websocket":
import websocket, asyncnet
export websocket except close
type WebSocket* = AsyncWebSocket
template newWebSocket*(args: varargs[untyped]): untyped =
newAsyncWebsocketClient(args)
template send*(ws: WebSocket, text: string): untyped =
ws.sendText(text)
template isClosed*(ws: WebSocket): bool =
bind isClosed
asyncnet.isClosed(ws.sock)
template close*(ws: WebSocket) =
discard websocket.close(ws)
elif websocketBackend == "jswebsockets":
{.error: "jswebsockets not yet supported".}
else:
{.error: "unknown websocket backend " & websocketBackend.}
nim-websock looks interesting for the reason that it doesn't use stdlib httpclient, but I haven't really needed to try it yet.
Don't think there a Nim wrapper for it: https://nng.nanomsg.org/man/v1.3.2/nng.7.html
There is. https://github.com/def-/nim-nanomsg
Async and threads isn't a problem. Just run the async event loop in only one of the threads for the websocket server.
That being said: you should avoid threads as much as you can. They make your code more complex and it's very difficult to use them for efficient parallelism (you'll end up with lock contention)
We are using https://github.com/treeform/ws in production at https://cxplanner.com - and have been doing that for 1 year now.
We are using it for normal notifications with push and pull, but also for managing simultaneous writing in the same online documents.
I get an error:
Error: type mismatch: got <MyThreadType, proc (myThreadVars: MyThreadVars): Future[system.void]{.gcsafe.}, MyThreadVars>
but expected one of:
proc createThread[TArg](t: var Thread[TArg];
tp: proc (arg: TArg) {.thread, nimcall.}; param: TArg)
first type mismatch at position: 2
required type for tp: proc (arg: TArg){.nimcall, gcsafe.}
but expression 'myThread' is of type: proc (myThreadVars: MyThreadVars): Future[system.void]{.gcsafe.}
1 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
Just a note: you shouldn't be creating a proc that is both async and a thread. Create a thread and then run async procs in it, something like:
proc myThread() {.thread.} =
asynCheck(asyncProc1)
waitFor(longRunningAsyncProc2)