#include #include #include #include #include #include std::string exec(const std::string &cmd) { std::array buffer; std::string result; std::unique_ptr pipe(popen(cmd.c_str(), "r"), pclose); if (!pipe) { throw std::runtime_error("popen() failed!"); } while (fgets(buffer.data(), static_cast(buffer.size()), pipe.get()) != nullptr) { result += buffer.data(); } return result; } std::string url_decode(const std::string& encoded) { int output_length; const auto decoded_value = curl_easy_unescape(nullptr, encoded.c_str(), static_cast(encoded.length()), &output_length); std::string result(decoded_value, output_length); curl_free(decoded_value); return result; } std::string process_file(const std::filesystem::path &path) { return exec("pandoc --template='templates/post.txt' -t plain '" + path.string() + "'");; } namespace route { std::string root() { return crow::mustache::load_text("index.html"); } crow::mustache::rendered_template blog() { std::string posts = ""; std::filesystem::path postsDir("posts"); std::vector> futures; for (auto const& entry : std::filesystem::directory_iterator{postsDir}) { if (entry.path().extension() == ".md") futures.emplace_back(std::async(std::launch::async, process_file, entry.path())); } for (auto& future : futures) { posts += future.get(); } auto page = crow::mustache::load("posts.html"); crow::mustache::context ctx( {{"posts", posts}} ); return page.render(ctx); } std::string post(const std::string &name) { std::string decoded_name = url_decode(name); if (std::filesystem::exists("posts/" + decoded_name)) return exec("pandoc --standalone --template templates/template.html './posts/" + decoded_name + "'"); else return std::string("

Not found

"); } }; int main() { crow::SimpleApp app; CROW_ROUTE(app, "/")(route::root); CROW_ROUTE(app, "/blog")(route::blog); CROW_ROUTE(app, "/blog/")(route::post); app.port(8080).multithreaded().run(); }