ctucx.git: oeffisearch

[nimlang] fast and simple tripplanner

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
import json, tables, os, httpcore, asynchttpserver, asyncdispatch, uri, strutils, posix
import types, endpoints/[suggestions, journeys, moreJourneys, refreshJourney]

when not defined(release):
  echo "running in development mode, for production compile with -d:release"
  import fileserver

var endpoints {.threadvar.}: Table[string, proc(data: JsonNode): Future[JsonNode] {.gcsafe.}]

proc removePidFile() =
  if getEnv("PID_FILE") != "":
    removeFile(getEnv("PID_FILE"))

proc CtrlCHook() {.noconv.} =
  echo "Ctrl+C fired! \nStopping Server now!"
  removePidFile()
  quit()

proc handleRequest(req: Request) {.async,gcsafe.} =
  var resp = NimHttpResponse(
    code: Http404,
    msg: $(%* {"status": "error", "msg": "ENDPOINT_NOT_FOUND", "data": {}}),
    headers: {"Content-Type": "application/json", "Access-Control-Allow-Origin": "*"}.newHttpHeaders,
  )

  try:
    if endpoints.hasKey($req.reqMethod & req.url.path):
      resp.code = Http200
      resp.msg  = $(%* {
        "status": "success",
        "msg": "",
        "data": (await endpoints[$req.reqMethod & req.url.path](parseJson(decodeUrl(req.url.query))))
      })

    else:
      when not defined(release):
        # development server
        resp = servePath(req)

  except notFoundException:
    resp.code = Http404
    resp.msg  = $(%* {"status": "error", "msg": getCurrentExceptionMsg().split("\n")[0], "data": {}})
  except:
    resp.code = Http500 
    resp.msg  = $(%* {"status": "error", "msg": getCurrentExceptionMsg().split("\n")[0], "data": {}})
    echo repr(getCurrentException())

  await req.respond(resp.code, resp.msg, resp.headers)

proc main() =
  setControlCHook(CtrlCHook)

  onSignal(SIGTERM):
    echo "Got SIGTERM! \nStopping Server now!"
    removePidFile()
    quit()

  if getEnv("CACHE_PATH") == "":
    echo "CACHE_PATH not set! Bye...."
    quit(1)
  else:
    discard existsOrCreateDir(getEnv("CACHE_PATH"))

  var port = 8081
  if getEnv("PORT") != "":
    port = parseInt(getEnv("PORT"))

  if getEnv("PID_FILE") != "":
    try:
      writeFile(getEnv("PID_FILE"), $getpid() & "\n")
      echo "pid-file \"" & getEnv("PID_FILE") & "\" crated"
    except:
      echo "Can't write pid file!"
      quit(1)


  endpoints = initTable[string, proc(data: JsonNode): Future[JsonNode] {.gcsafe.}]()

  endpoints[$HttpGet & "/suggestions"]    = suggestionsEndpoint
  endpoints[$HttpGet & "/journeys"]       = journeysEndpoint
  endpoints[$HttpGet & "/moreJourneys"]   = moreJourneysEndpoint
  endpoints[$HttpGet & "/refreshJourney"] = refreshJourneyEndpoint

  let server = newAsyncHttpServer()

  when not defined(release):
    initFileserver()

  echo "starting webserver on port " & $port
  waitFor server.serve(Port(port), handleRequest)

main()