lib/server.nim
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 |
import asynchttpserver2, asyncdispatch, times, strutils, pegs, strtabs, cgi, logging
import types, utils, api_v1
proc getReqInfo(req: Request): string =
var url = req.url.path
if req.url.anchor != "":
url = url & "#" & req.url.anchor
if req.url.query != "":
url = url & "?" & req.url.query
return req.hostname & " " & req.reqMethod & " " & url
proc handleCtrlC() {.noconv.} =
echo ""
info("Exiting...")
quit()
proc parseApiUrl(req: Request): ResourceInfo =
var matches = @["", "", ""]
if req.url.path.find(PEG_URL, matches) != -1:
result.version = matches[0]
result.resource = matches[1]
result.id = matches[2]
else:
raise newException(EInvalidRequest, req.getReqInfo())
proc route(req: Request, LS: LiteStore): Response =
if req.url.path == "/favicon.ico":
result.code = Http200
result.content = LS.favicon
result.headers = {"Content-Type": "image/x-icon"}.newStringTable
return result
try:
var info = req.parseApiUrl
if info.version == "v1" and info.resource.match(peg"^docs / info$"):
return api_v1.route(req, LS, info.resource, info.id)
else:
if info.version != "v1":
return resError(Http400, "Bad request - Invalid API version: $1" % info.version)
else:
if info.resource.decodeURL.strip == "":
return resError(Http400, "Bad request - No resource specified" % info.resource)
else:
return resError(Http400, "Bad request - Invalid resource: $1" % info.resource)
except:
let e = getCurrentException()
let trace = e.getStackTrace()
return resError(Http500, "Internal Server Error: $1" % getCurrentExceptionMsg(), trace)
setControlCHook(handleCtrlC)
proc serve*(LS: LiteStore) =
var server = newAsyncHttpServer()
proc handleHttpRequest(req: Request): Future[void] {.async.} =
info(getReqInfo(req).replace("$", "$$"))
let res = req.route(LS)
await req.respond(res.code, res.content, res.headers)
info(LS.appname & " v" & LS.appversion & " started on " & LS.address & ":" & $LS.port & ".")
if LS.mount:
info("Mirroring datastore changes to: " & LS.directory)
asyncCheck server.serve(LS.port.Port, handleHttpRequest, LS.address)
|