Thank you @enthus1ast and everyone for showing me the way. Now all code
compiles without errors or warnings.
import asynchttpserver, asyncdispatch
import tables
import times
import oids
import cookies
import strformat
import strtabs
import strutils
type
Session = ref object
id: string
map: TableRef[string, string]
request_time: DateTime
callback: proc (id: string): Future[void]
type
AsyncHttpSessions = ref object of RootObj
pool: TableRef[string, Session]
session_timeout: int
sleep_time: int
proc sessions_manager(self: AsyncHttpSessions): Future[void] {.async.} =
while true:
await sleepAsync(self.sleep_time)
if self.pool == nil:
continue
echo "Number of active sessions: ", self.pool.len
echo "check for sessions timeout..."
var to_del = newSeq[string]()
for key, value in self.pool:
if (now() - self.pool[key].request_time).inSeconds >
self.session_timeout:
echo "session id timeout:", key
to_del.add(key)
for key in to_del:
if self.pool[key].callback != nil:
await self.pool[key].callback(key)
echo "the session will be deleted:", key
self.pool.del(key)
proc set_session(self: AsyncHttpSessions): Session =
let session_id = genOid()
return (self.pool[$session_id] = Session(
id: $session_id,
map: newTable[string, string](),
request_time: now(),
callback: nil
); self.pool[$session_id])
proc get_session(self: AsyncHttpSessions, id: string): Session =
(self.pool[id].request_time = now(); self.pool[id])
proc new_async_http_sessions(
sleep_time: int = 5000,
session_timeout: int = 3600): AsyncHttpSessions =
let self = AsyncHttpSessions()
self.sleep_time = sleep_time
self.session_timeout = session_timeout
self.pool = newTable[string, Session]()
asyncCheck self.sessions_manager()
return self
proc login(): string =
return """
<!Doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
</head>
<body>
<form action="/login" method="post">
Username: <input type="text" name="username" value="test"><br/>
Password: <input type="password" name="password" value="12345678"><br/>
<input type="submit">
</form>
</body>
</html>
"""
proc cb(req: Request, sessions: AsyncHttpSessions) {.async.} =
if req.url.path == "/login" and req.reqMethod == HttpPost:
var params = initTable[string, string]()
for part in req.body.split('&'):
let pair = part.split('=')
if pair.len == 2:
params[pair[0]] = pair[1]
if params.hasKey("username") and params["username"] == "test" and
params.hasKey("password") and params["password"] == "12345678":
proc timeout_session(id: string) {.async.} =
echo "expired session:", id
var session = sessions.set_session()
session.map["username"] = params["username"]
session.map["password"] = params["password"]
session.callback = timeout_session
let headers = newHttpHeaders([("Set-Cookie",
&"session={session.id}")])
await req.respond(Http200, &"""Hello User
{session.map["username"]}""", headers)
else:
await req.respond(Http200, login())
else:
var id = ""
if req.headers.hasKey("Cookie"):
let cookies = parseCookies(req.headers["Cookie"])
if cookies.hasKey("session"):
id = cookies["session"]
if id != "" and sessions.pool.hasKey(id):
var session = sessions.get_session(id)
await req.respond(Http200, &"""Hello User {session.map["username"]}
Again :-)""")
else:
await req.respond(Http200, login())
proc main() =
let server = newAsyncHttpServer()
let sessions = newAsyncHttpSessions(
sleep_time=1000,
session_timeout=30
)
waitFor server.serve(
Port(8080),
proc (req: Request): Future[void] = cb(req, sessions)
)
main()
Run