I have two files, the generic Server in the library, and the App. Server doesn't know the concrete type of the Session, it's only defined later in the App.
How to write such code, the way I wrote it below doesn't work as for some reason I can't modify global var object in the closure. (Error: 'sessions' is of type <var Sessions[system.string]> which cannot be captured as it would violate memory safety, declared here: play.nim(11, 28); using '-d:nimNoLentIterators' helps in some cases).
# server.nim ------------------------------------------
import std/[httpcore, asynchttpserver, asyncnet, tables, asyncdispatch]
type SessionData[S] = ref object
session: S
type Sessions[S] = Table[string, SessionData[S]]
proc build_http_handler[S](sessions: var Sessions[S]): auto =
return proc (req: Request): Future[void] {.async, gcsafe.} =
let session_id = "someid"
if session_id notin sessions: sessions[session_id] = SessionData[S]()
let session = sessions[session_id]
return req.respond(Http200, $(session.session))
proc run_server*[S] =
var sessions: Sessions[S]
var server = new_async_http_server()
async_check server.serve(Port(5000), build_http_handler(sessions), "localhost")
run_forever()
# app.nim ------------------------------------------
run_server[string]()
Using ref for this case feels really wrong.
In this specific case using value type and var looks like a much better approach. It clearly specifies intention and behaviour, that there's some mutable variable and that the argument going to be mutate.
Version with ref, while works, doesn't convey the intention and looks more like hack to overcame Nim limitation.
Found another way to implement it
# server.nim ------------------------------------------
import std/[httpcore, asynchttpserver, asyncnet, tables, asyncdispatch]
type SessionData[S] = ref object
session: S
type Sessions[S] = Table[string, SessionData[S]]
proc run_server*[S] =
var sessions: Sessions[S]
proc http_handler(req: Request): Future[void] {.async, gcsafe.} =
let session_id = "someid"
if session_id notin sessions: sessions[session_id] = SessionData[S]()
let session = sessions[session_id]
return req.respond(Http200, $(session.session))
var server = new_async_http_server()
async_check server.serve(Port(5000), http_handler, "localhost")
run_forever()
# app.nim ------------------------------------------
run_server[string]()