view service/rfid_pn532/graphserver.nim @ 397:0bc26b4fc427

a little further on toplevel nim code. event passing is not working Ignore-this: 86bdf86c796f2cf2ce2f245a0468c4eb
author drewp@bigasterisk.com
date Thu, 21 Feb 2019 22:37:04 -0800
parents ff588658de31
children 56af0ca2db10
line wrap: on
line source

import asynchttpserver, asyncdispatch, asyncnet, strtabs, sequtils, times, os, strutils, strformat

type
  GraphServer* = ref object of RootObj
    port*: int
    clients: seq[AsyncSocket]
    previousUpdateTime: int
    httpServer: AsyncHttpServer
    serverReady: Future[void]
    
proc handleCORS(req: Request) {.async.} =
  await req.respond(Http204, "", newHttpHeaders({
    "Access-Control-Allow-Origin": "*",
    "Connection": "close"}))

proc handle404(req: Request) {.async.} =
  let headers = newHttpHeaders({"Content-Type": "text/plain",
                                "Connection": "close"})

  await req.respond(Http404, "File not found", headers)
  req.client.close()

proc handleSSE(self: GraphServer, req: Request) {.async.} =
  let headers = newHttpHeaders({"Content-Type": "text/event-stream",
                                "Access-Control-Allow-Origin": "*",
                                "Cache-Control": "no-cache",
                                "Connection": "keep-alive"})

  await req.client.send("HTTP/1.1 200 OK\c\L")
  await req.sendHeaders(headers)
  await req.client.send("\c\L:ok\n\n")
  self.clients.add(req.client)

proc handleConnections(self: GraphServer, req: Request) {.async.} =
  let clientCount = self.clients.len
  let headers = newHttpHeaders({"Content-Type": "text/plain",
                                "Access-Control-Allow-Origin": "*",
                                "Cache-Control": "no-cache",
                                "Connection": "close"})

  await req.respond(Http200, $clientCount, headers)
  req.client.close()

proc requestCallback(self: GraphServer, req: Request) {.async.} =
  if req.reqMethod == HttpOptions:
    asyncCheck handleCORS(req)
  else:
    case req.url.path
    of "/connections": asyncCheck self.handleConnections(req)
    of "/sse": asyncCheck self.handleSSE(req)
    else: asyncCheck handle404(req)

proc newGraphServer*(port: int): GraphServer =
  new(result)
  result.port = port
  result.previousUpdateTime = toInt(epochTime() * 1000)

  result.httpServer = newAsyncHttpServer(true)
  let self = result
  self.serverReady = self.httpServer.serve(
    Port(self.port),
    proc (req: Request): Future[void] = self.requestCallback(req),
    address="0.0.0.0")
  asyncCheck self.serverReady
  echo "Listening on " & $self.port
  

proc checkClients(self: GraphServer) =
  self.clients = self.clients.filterIt(not it.isClosed())

proc pingClients(self: GraphServer) {.async.} =
  let currentTime = toInt(epochTime() * 1000)

  if currentTime - self.previousUpdateTime < 1000:
    return

  for client in self.clients:
    if not client.isClosed():
      asyncCheck client.send("data: " & $currentTime & "\n\n")

  self.previousUpdateTime = toInt(epochTime() * 1000)

proc run*(self: GraphServer) =
  while true:
    self.checkClients()
    asyncCheck self.pingClients()
    poll()


# Replace graph contents
proc setGraph*(self: GraphServer) =
  echo "graph replaced"