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

Reply via email to