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)