145 lines
3.9 KiB
D
145 lines
3.9 KiB
D
|
import std.experimental.logger;
|
||
|
import std.range;
|
||
|
import std.string;
|
||
|
import std.stdio;
|
||
|
import std.typecons;
|
||
|
|
||
|
import vibe.d;
|
||
|
|
||
|
import article;
|
||
|
import page;
|
||
|
import project;
|
||
|
import watcher;
|
||
|
|
||
|
/**
|
||
|
* Internal list of articles by slug.
|
||
|
*/
|
||
|
Article[string] articles;
|
||
|
Page[string] pages;
|
||
|
Project[string] projects;
|
||
|
|
||
|
immutable string articleSortPred = "a.firstPublished > b.firstPublished";
|
||
|
Article*[] articleList;
|
||
|
immutable string pageSortedPred = "a.title < b.title";
|
||
|
Page*[] pageList;
|
||
|
Project[] projectList;
|
||
|
|
||
|
enum OutputType {
|
||
|
HTML,
|
||
|
MARKDOWN
|
||
|
}
|
||
|
|
||
|
const string MIME_MARKDOWN = "text/markdown";
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Get's the document type for the given slug based on extension
|
||
|
* and returns the slug without extension and the document type.
|
||
|
*/
|
||
|
private OutputType getOutputType(ref string slug) {
|
||
|
if (slug.endsWith(".md")) {
|
||
|
slug = chomp(slug, ".md");
|
||
|
return OutputType.MARKDOWN;
|
||
|
} else if (slug.endsWith(".html")){
|
||
|
// If explicitly asking for HTML, we'll return HTML
|
||
|
slug = chomp(slug, ".html");
|
||
|
return OutputType.HTML;
|
||
|
} else {
|
||
|
// If in the future, for any reason, we no longer use HTML
|
||
|
// this allows to us to keep the current urls with an option
|
||
|
// to change the output in the future.
|
||
|
return OutputType.HTML;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void getSingle(T, string templ)(ref T[string] array, HTTPServerRequest req, HTTPServerResponse res) {
|
||
|
string slug = req.params["slug"];
|
||
|
OutputType outputType = getOutputType(slug);
|
||
|
|
||
|
enforceHTTP(slug in array, HTTPStatus.notFound, "Page not found");
|
||
|
T content = array[slug];
|
||
|
res.headers["Cache-Control"] = "public";
|
||
|
switch(outputType) with (OutputType) {
|
||
|
case MARKDOWN:
|
||
|
res.writeBody(content.contentSource, MIME_MARKDOWN);
|
||
|
break;
|
||
|
default:
|
||
|
case HTML:
|
||
|
res.render!(templ, content);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generates response for /posts/:slug and /palen/:slug.
|
||
|
*/
|
||
|
void articleGetSingle(HTTPServerRequest req, HTTPServerResponse res) {
|
||
|
getSingle!(Article, "pages/article.dt")(articles, req, res);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generates response for /posts/ and /palen/
|
||
|
*/
|
||
|
void articleGetOverview(HTTPServerRequest req, HTTPServerResponse res) {
|
||
|
res.headers["Cache-Control"] = "public";
|
||
|
render!("pages/article-list.dt", articleList)(res);
|
||
|
}
|
||
|
|
||
|
void projectGetOverview(HTTPServerRequest req, HTTPServerResponse res) {
|
||
|
res.headers["Cache-Control"] = "public";
|
||
|
render!("pages/project-list.dt", projectList)(res);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generate response for a page
|
||
|
*/
|
||
|
void pageGet(HTTPServerRequest req, HTTPServerResponse res) {
|
||
|
if (("slug" in req.params) is null) {
|
||
|
req.params.addField("slug", "index");
|
||
|
}
|
||
|
getSingle!(Page, "pages/page.dt")(pages, req, res);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generates response whenever an error occurs.
|
||
|
*/
|
||
|
@safe
|
||
|
void errorPage(HTTPServerRequest req, HTTPServerResponse res, HTTPServerErrorInfo error) {
|
||
|
render!("pages/error.dt", error)(res);
|
||
|
}
|
||
|
|
||
|
void main() {
|
||
|
//articles["hello-world"] = new Article("hello-world.yamd");
|
||
|
|
||
|
HTTPServerSettings settings = new HTTPServerSettings;
|
||
|
settings.bindAddresses = ["0.0.0.0"];
|
||
|
settings.port = 3465;
|
||
|
settings.serverString = "zeg ik lekker niet";
|
||
|
settings.errorPageHandler = toDelegate(&errorPage);
|
||
|
settings.keepAliveTimeout = dur!"seconds"(60);
|
||
|
debug {
|
||
|
settings.accessLogToConsole = true;
|
||
|
}
|
||
|
|
||
|
URLRouter router = new URLRouter;
|
||
|
router.get("/posts/:slug", &articleGetSingle);
|
||
|
router.get("/palen/:slug", &articleGetSingle);
|
||
|
router.get("/posts/", &articleGetOverview);
|
||
|
router.get("/palen/", &articleGetOverview);
|
||
|
router.get("/projects/", &projectGetOverview);
|
||
|
router.get("/projecten/", &projectGetOverview);
|
||
|
router.get("/static/*", serveStaticFiles("./public/"));
|
||
|
router.get("/:slug", &pageGet);
|
||
|
router.get("/", &pageGet);
|
||
|
|
||
|
listenHTTP(settings, router);
|
||
|
runTask({
|
||
|
initPages!(Page, pageSortedPred)(pages, pageList, "pages");
|
||
|
});
|
||
|
runTask({
|
||
|
initPages!(Article, articleSortPred)(articles, articleList, "articles");
|
||
|
});
|
||
|
runApplication();
|
||
|
}
|