/* docserver.du -- embedded documentation server Self-referential script that launches the HTTP server and registers itself to handle all requests. */ // our lightweight markdown parser md = require("markdown") // context() is how http_server gives access to request info ctx = context() // server setup: ctx is nil run from the CLI if ctx == nil then // setup server server = http_server({port = 5150}) print("Doc server running at http://localhost:5150") // register this script to handle all GET requests server.route("GET", "/") // inject a load tester //spawn("stdlib/docserver/load-test.du", nil) // start server and wait for it to stop server.start() // server stopped, usually ctl+c from CLI print("Server stopped.") exit() end // if context is populated, we fall down here // to handle each request for http_server req = ctx.request() res = ctx.response() path = req.path // check if path is a static file (images, fonts, stylesheets) if contains(path, ~\.(png|html|jpg|jpeg|gif|webp|ico|woff|woff2|css|js)$~) then filepath = replace(path, ~^/~, "") // exit and tell server to serve the file res.file(filepath) end // read -config "docserver_test=true" // disabled cache for easy dev config = sys("-config") dev_mode = config ? config.docserver_test : false // initialize cache (in-memory, flushes on restart) cache = datastore("docserver") // add query to cache key if exists cache_key = path == "" ? "/" : path if type(req.query) == "array" then cache_key = "?" + join(req.query, "+") elseif req.query then cache_key = "?" + req.query end if not dev_mode then // check cache (unless in development mode) cached_html = cache.get(cache_key) if cached_html != nil then print("Serving from cache: " + cache_key) // return the cached file to the http server res.html(cached_html) end end // handles local files (usually for doc authors) // and falls back to embedded files function smart_load(filename) var text = "" print(filename) print(current_dir()) try text = load(current_dir() + "/" + filename) catch(err) try text = load(filename) catch(err) text = load("/EMBED/" + filename) end end return text end content = "" if path == "/" or path == "" then // index is really README.md try content = smart_load("README.md") catch (e) content = "Error loading README.md" end elseif path == "/lookup" then // search search_term = req.query.search // lookup endpoint: search for docs and redirect to the first match if search_term != nil and search_term != "" then var filename = "docs/reference/{{search_term}}.md" if file_exists(filename) or file_exists("/EMBED/" + filename) then res.redirect("/" + filename) end end var msg = "" if search_term then msg = "Can't find a doc for `{{search_term}}`. " end // no search term or couldn't resolve - show search prompt content = """ # Search {{msg}} Enter a search term to find documentation for a function, module, or keyword. """ else // for any other path, try to load as a markdown file filepath = replace(path, ~^/~, "") try content = smart_load(filepath) catch (e) res.html("

404 Not Found

" + filepath + "

", 404) end end // extract "Documentation from:" line to move to footer doc_source = "" content = replace(content, ~^Documentation from: .+\n?~, function(match) doc_source = "" + match + "" return "" end) // Apply markdown formatter html_content = md.html(content) // build nav bar (only on non-home pages) nav_html = "" if path != "/" and path != "" then nav_html = """ """ end // wrap in HTML template html = """ Duso Docs {{path}}
{{nav_html}} {{html_content}}
""" // cache the rendered HTML (unless in development mode) if not dev_mode then cache.set(cache_key, html) end // return our response to the http server res.html(html)