/ server / server.nim
server.nim
  1  #            NimYAML - YAML implementation in Nim
  2  #        (c) Copyright 2015 Felix Krause
  3  #
  4  #    See the file "copying.txt", included in this
  5  #    distribution, for details about the copyright.
  6  
  7  import jester, parseopt, asyncdispatch, json, streams, strutils
  8  import packages/docutils/rstgen, packages/docutils/highlite, options
  9  import ../yaml, ../yaml/parser, ../yaml/presenter, server_cfg
 10  
 11  router nyRouter:
 12    get "/webservice/":
 13      resp(Http200, [("Content-Type", "text/plain")], "I am a friendly NimYAML parser webservice.")
 14    post "/webservice/":
 15      var
 16        resultNode = newJObject()
 17        msg: string
 18        retStatus = Http200
 19        contentType = "application/json"
 20        headers = @[("Access-Control-Allow-Origin", "*"), ("Pragma", "no-cache"),
 21          ("Cache-Control", "no-cache"), ("Expires", "0")]
 22        dumper: Dumper
 23      try:
 24        case @"style"
 25        of "minimal": dumper.setMinimalStyle()
 26        of "explanatory": dumper.setExplanatoryStyle()
 27        of "default": dumper.setDefaultStyle()
 28        of "json": dumper.setJsonStyle()
 29        of "block": dumper.setBlockOnlyStyle()
 30        of "tokens":
 31          try:
 32            var
 33              output = "+STR\n"
 34              parser = initYamlParser(false)
 35              events = parser.parse(newStringStream(@"input"))
 36            for event in events: output.add(parser.display(event) & "\n")
 37            output &= "-STR"
 38            resultNode["code"] = %0
 39            resultNode["output"] = %output
 40            msg = resultNode.pretty
 41          except YamlStreamError as e:
 42            raise e.parent
 43        else:
 44          retStatus = Http400
 45          msg = "Invalid style: " & escape(@"style")
 46          contentType = "text/plain;charset=utf8"
 47        if len(msg) == 0:
 48          var
 49            output = newStringStream()
 50            highlighted = ""
 51          dumper.transform(newStringStream(@"input"), output, @"style" == "explanatory")
 52  
 53          # syntax highlighting (stolen and modified from stlib's rstgen)
 54          var g: GeneralTokenizer
 55          g.initGeneralTokenizer(output.data)
 56          while true:
 57            g.getNextToken(langYaml)
 58            case g.kind
 59            of gtEof: break
 60            of gtNone, gtWhitespace:
 61              highlighted.add(substr(output.data, g.start, g.length + g.start - 1))
 62            else:
 63              highlighted.addf("<span class=\"$2\">$1</span>",
 64                esc(outHtml, substr(output.data, g.start, g.length+g.start-1)),
 65                tokenClassToStr[g.kind])
 66  
 67          resultNode["code"] = %0
 68          resultNode["output"] = %highlighted
 69          msg = resultNode.pretty
 70      except YamlParserError as e:
 71        resultNode["code"] = %1
 72        resultNode["line"] = %e.mark.line
 73        resultNode["column"] = %e.mark.column
 74        resultNode["message"] = %e.msg
 75        resultNode["detail"] = %e.lineContent
 76        msg = resultNode.pretty
 77      except YamlPresenterJsonError as e:
 78        resultNode["code"] = %2
 79        resultNode["message"] = %e.msg
 80        msg = resultNode.pretty
 81      except CatchableError as e:
 82        msg = "Name: " & $e.name & "\nMessage: " & e.msg &
 83            "\nTrace:\n" & e.getStackTrace
 84        retStatus = Http500
 85        contentType = "text/plain;charset=utf-8"
 86      headers.add(("Content-Type", contentType))
 87      resp retStatus, headers, msg
 88  
 89  proc main(port: int, address: string) =
 90    let settings = newSettings(port=port.Port, bindAddr=address, staticDir=shareDir())
 91    var jester = initJester(nyrouter, settings=settings)
 92    jester.serve()
 93  
 94  when isMainModule:
 95    var
 96      port = 5000
 97      address = "127.0.0.1"
 98    for kind, key, value in getOpt():
 99      case kind
100      of cmdArgument:
101        echo "unexpected positional argument"
102        quit 1
103      of cmdLongOption, cmdShortOption:
104        case key
105        of "p", "port":
106          port = parseInt(value)
107        of "a", "address":
108          address = value
109        else:
110          echo "Unknown option: ", key
111          quit 1
112      of cmdEnd:
113        discard
114    main(port, address)