precompiled headers

main
Brett 2023-09-07 00:36:09 -04:00
parent 0c8ab4f082
commit 7c4c4ee28f
16 changed files with 415 additions and 190 deletions

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/static/css/index.css">
<style>
{{@../static/css/menu_bar.css}}
{{@../static/css/body.css}}
</style>
<meta charset="UTF-8">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="author" content="Brett">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{$SITE_TITLE}}</title>
</head>
{{@body_begin.part}}
<div class="body">
<div class="center">
{{CURRENT_POST}}
</div>
</div>
{{@body_end.part}}
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/static/css/index.css">
<style>
{{@../static/css/menu_bar.css}}
{{@../static/css/body.css}}
</style>
<meta charset="UTF-8">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="author" content="Brett">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{$SITE_TITLE}}</title>
</head>
{{@body_begin.part}}
<div class="body">
<div class="center">
{{CURRENT_POST}}
</div>
</div>
{{@body_end.part}}
</html>

View File

@ -9,7 +9,8 @@
#include <blt/std/hashmap.h>
//#define CROW_STATIC_DIRECTORY "/home/brett/projects/cpp/crowsite/crow_test/static/"
#define CROWSITE_STATIC_DIRECTORY "/home/brett/Documents/code/c++/crowsite/crow_test/static/"
#undef CROW_STATIC_DIRECTORY
#define CROW_STATIC_DIRECTORY "/home/brett/Documents/code/c++/crowsite/crow_test/static/"
//#define SITE_FILES_PATH "/home/brett/projects/cpp/crowsite/crow_test"
#define CROWSITE_FILES_PATH "/home/brett/Documents/code/c++/crowsite/crow_test"
#define CROWSITE_STATIC_ENDPOINT "/static/<path>"

View File

@ -8,6 +8,7 @@
#ifndef CROWSITE_CROW_PCH_H
#define CROWSITE_CROW_PCH_H
#include <crowsite/config.h>
#include "crow/query_string.h"
#include "crow/http_parser_merged.h"
#include "crow/ci_map.h"

View File

@ -8,69 +8,16 @@
#ifndef CROWSITE_HOME_H
#define CROWSITE_HOME_H
#include <crowsite/site/cache.h>
#include <crowsite/util/crow_session_util.h>
#include <crowsite/util/crow_conversion.h>
namespace cs
{
inline crow::response handle_root_page(const site_params& params)
{
//auto page = crow::mustache::load("index.html"); //
//return "<html><head><title>Hello There</title></head><body><h1>Suck it " + name + "</h1></body></html>";
// BLT_TRACE(req.body);
// for (const auto& h : req.headers)
// BLT_TRACE("Header: %s = %s", h.first.c_str(), h.second.c_str());
// BLT_TRACE(req.raw_url);
// BLT_TRACE(req.url);
// BLT_TRACE(req.remote_ip_address);
// for (const auto& v : req.url_params.keys())
// BLT_TRACE("URL: %s = %s", v.c_str(), req.url_params.get(v));
if (params.name.ends_with(".html"))
{
checkAndUpdateUserSession(params.app, params.req);
auto& session = params.app.get_context<Session>(params.req);
auto s_clientID = session.get("clientID", "");
auto s_clientToken = session.get("clientToken", "");
auto user_perms = cs::getUserPermissions(cs::getUserFromID(s_clientID));
crow::response handle_login_request(const crow::request& req, CrowApp& app);
crow::mustache::context ctx;
cs::context context;
crow::response handle_root_page(const site_params& params);
generateRuntimeContext(params, context);
// pass perms in
if (user_perms & cs::PERM_ADMIN)
ctx["_admin"] = true;
if (cs::isUserLoggedIn(s_clientID, s_clientToken))
{
ctx["_logged_in"] = true;
} else
{
ctx["_not_logged_in"] = true;
}
// we don't want to pass all get parameters to the context to prevent leaking information
auto referer = params.req.url_params.get("referer");
if (referer)
ctx["referer"] = referer;
auto page = crow::mustache::compile(params.engine.fetch(params.name, context));
return page.render(ctx);
}
return params.engine.fetch("default.html");
}
inline crow::response handle_auth_page(const site_params& params)
{
if (isUserAdmin(params.app, params.req))
return redirect("/login.html");
return handle_root_page(params);
}
crow::response handle_auth_page(const site_params& params);
}

View File

@ -0,0 +1,20 @@
#pragma once
/*
* Created by Brett on 01/09/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#ifndef CROWSITE_ROUTING_H
#define CROWSITE_ROUTING_H
#include <crowsite/crow_pch.h>
#include "crowsite/site/cache.h"
namespace cs
{
void establishHomeRoutes(CrowApp& app, CacheEngine& engine);
void establishProjectRoutes(CrowApp& app, CacheEngine& engine);
}
#endif //CROWSITE_ROUTING_H

View File

@ -7,29 +7,110 @@
#include <sqlite3.h>
#include <type_traits>
#include <filesystem>
#include "blt/std/assert.h"
namespace cs::sql
{
class sql_error : public std::runtime_error
{
public:
sql_error(const std::string& error): std::runtime_error(error)
{}
};
static int prepareStatement(sqlite3* db, const std::string& sqlStatement, sqlite3_stmt** ppStmt)
{
return sqlite3_prepare_v2(db, sqlStatement.c_str(), static_cast<int>(sqlStatement.size()) + 1, ppStmt, nullptr);
}
class statement
class database
{
friend class statement_base_helper;
private:
sqlite3_stmt* stmt = nullptr;
std::string path;
sqlite3* db;
int err;
public:
statement(sqlite3* db, const std::string& statement): db(db)
database(const std::string& dbLocation): path(dbLocation)
{
err = prepareStatement(db, statement, &stmt);
if (err)
BLT_ERROR("Failed to execute statement, error code %d, error: %s.", err, sqlite3_errstr(err));
std::filesystem::create_directories(dbLocation.substr(0, dbLocation.find_last_of('/') + 1));
if (int err = sqlite3_open_v2(
path.c_str(), &db,
SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX,
nullptr
) != SQLITE_OK)
{
BLT_FATAL("Unable to create database connection! err %d msg %s", err, sqlite3_errstr(err));
std::exit(1);
}
}
database(database&& move)
{
db = move.db;
path = move.path;
move.db = nullptr;
}
database& operator=(database&& move)
{
db = move.db;
path = move.path;
move.db = nullptr;
return *this;
}
database(const database& copy) = delete;
database& operator=(const database& copy) = delete;
~database()
{
sqlite3_close_v2(db);
}
};
class statement_base_helper
{
protected:
sqlite3_stmt* stmt = nullptr;
int err;
statement_base_helper(const database& db, const std::string& statement, bool throw_errors)
{
err = prepareStatement(db.db, statement, &stmt);
if (err != SQLITE_OK)
{
if (throw_errors)
{
BLT_THROW(std::runtime_error(
"Failed to prepare statement '" + statement + "', error code " + std::to_string(err) + ", error: " +
sqlite3_errstr(err)));
} else
BLT_ERROR("Failed to prepare statement, error code %d, error: %s.", err, sqlite3_errstr(err));
}
}
};
class statement : public statement_base_helper
{
public:
statement(statement&& move) = delete;
statement(const statement& copy) = delete;
statement& operator=(statement&& move) = delete;
statement& operator=(const statement& copy) = delete;
statement(const database& db, const std::string& statement, bool throw_errors = true): statement_base_helper(db, statement, throw_errors)
{}
statement(const database* db, const std::string& statement, bool throw_errors = true): statement_base_helper(*db, statement, throw_errors)
{}
/**
* @return true if the last statement failed. Should be checked after construction!
*/
@ -121,6 +202,12 @@ namespace cs::sql
};
inline void auto_statement(const database* db, const std::string& stmt, bool throw_errors = true){
statement s(db, stmt, throw_errors);
if (!s.execute() && throw_errors)
BLT_THROW(sql_error("Unable to execute statement '" + stmt + "'. Error: " + std::to_string(s.error()) + sqlite3_errstr(s.error())));
}
}
#endif //CROWSITE_SQL_HELPER_H

View File

@ -14,6 +14,8 @@
namespace cs
{
constexpr auto session_age = 24 * 60 * 60;
constexpr auto cookie_age = 180 * 24 * 60 * 60;
struct site_params
{
@ -37,4 +39,9 @@ namespace cs
void generateRuntimeContext(const site_params& params, cs::context& context);
}
#define CS_SESSION cs::checkAndUpdateUserSession(app, req); \
auto& session = app.get_context<Session>(req); \
auto s_clientID = session.get("clientID", ""); \
auto s_clientToken = session.get("clientToken", ""); \
#endif //CROWSITE_CROW_SESSION_UTIL_H

@ -1 +1 @@
Subproject commit d3ed46686eb0667c9824fbba5f90519efd2a50c3
Subproject commit 215220f98b0ac4a87fe4a233de16650cf6d0b968

View File

@ -17,7 +17,7 @@ using namespace blt;
namespace cs
{
sqlite3* user_database;
cs::sql::database* user_database;
// https://stackoverflow.com/questions/5288076/base64-encoding-and-decoding-with-openssl
@ -191,28 +191,15 @@ namespace cs
void auth::init()
{
// TODO: proper multithreading
auto path = cs::fs::createDataFilePath("db/");
auto dbname = "users.sqlite";
auto full_path = path + dbname;
BLT_TRACE("Using %s for users database", full_path.c_str());
std::filesystem::create_directories(path);
if (int err = sqlite3_open_v2(full_path.c_str(), &user_database,
SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX,
nullptr
) != SQLITE_OK)
{
BLT_FATAL("Unable to create database connection! err %d msg %s", err, sqlite3_errstr(err));
std::exit(1);
}
const auto path = cs::fs::createDataFilePath("db/users.sqlite");
BLT_TRACE("Using %s for users database", path.c_str());
user_database = new sql::database(path);
sql::statement v {
user_database,
"SELECT SQLITE_VERSION()"
};
if (v.fail())
BLT_WARN("Failed to create statement with error code: %d msg: %s", v.error(), sqlite3_errstr(v.error()));
if (!v.execute())
BLT_WARN("Failed to execute statement with error code: %d msg: %s", v.error(), sqlite3_errstr(v.error()));
@ -237,6 +224,6 @@ namespace cs
void auth::cleanup()
{
sqlite3_close_v2(user_database);
delete(user_database);
}
}

View File

@ -136,6 +136,7 @@ namespace cs
case TokenType::CLOSE:
return "CLOSE";
}
throw LexerSyntaxError("Unable to determine type of token");
}
struct Token
@ -254,6 +255,7 @@ namespace cs
default:
blt_throw(LexerSyntaxError("Weird token found while parsing tokens, type: " + decodeName(next.type)));
}
return false;
}
bool expr(const context& context)
@ -298,11 +300,6 @@ namespace cs
return str[index] == '{' && str[index + 1] == '{' && str[index + 2] == c;
}
static std::string consumeToEndTemplate(const std::string& tokenName)
{
}
static void getTagLocations(std::vector<size_t>& tagLocations, const std::string& tag, const std::string& data)
{
RuntimeLexer lexer(data);

View File

@ -4,8 +4,103 @@
* See LICENSE file for license detail
*/
#include <crowsite/site/home.h>
#include <crowsite/util/crow_conversion.h>
#include <blt/std/logging.h>
namespace cs
{
crow::response handle_root_page(const site_params& params)
{
//auto page = crow::mustache::load("index.html"); //
//return "<html><head><title>Hello There</title></head><body><h1>Suck it " + name + "</h1></body></html>";
// BLT_TRACE(req.body);
// for (const auto& h : req.headers)
// BLT_TRACE("Header: %s = %s", h.first.c_str(), h.second.c_str());
// BLT_TRACE(req.raw_url);
// BLT_TRACE(req.url);
// BLT_TRACE(req.remote_ip_address);
// for (const auto& v : req.url_params.keys())
// BLT_TRACE("URL: %s = %s", v.c_str(), req.url_params.get(v));
if (params.name.ends_with(".html"))
{
checkAndUpdateUserSession(params.app, params.req);
auto& session = params.app.get_context<Session>(params.req);
auto s_clientID = session.get("clientID", "");
auto s_clientToken = session.get("clientToken", "");
auto user_perms = cs::getUserPermissions(cs::getUserFromID(s_clientID));
crow::mustache::context ctx;
cs::context context;
generateRuntimeContext(params, context);
// pass perms in
if (user_perms & cs::PERM_ADMIN)
ctx["_admin"] = true;
if (cs::isUserLoggedIn(s_clientID, s_clientToken))
{
ctx["_logged_in"] = true;
} else
{
ctx["_not_logged_in"] = true;
}
// we don't want to pass all get parameters to the context to prevent leaking information
auto referer = params.req.url_params.get("referer");
if (referer)
ctx["referer"] = referer;
auto page = crow::mustache::compile(params.engine.fetch(params.name, context));
return page.render(ctx);
}
return params.engine.fetch("default.html");
}
crow::response handle_auth_page(const site_params& params)
{
if (isUserAdmin(params.app, params.req))
return redirect("/login.html");
return handle_root_page(params);
}
crow::response handle_login_request(const crow::request& req, CrowApp& app)
{
cs::parser::Post pp(req.body);
auto& session = app.get_context<Session>(req);
std::string user_agent;
for (const auto& h : req.headers)
if (h.first == "User-Agent")
{
user_agent = h.second;
break;
}
// either cs::redirect to clear the form if failed or pass user to index
if (cs::checkUserAuthorization(pp))
{
cs::cookie_data data = cs::createUserAuthTokens(pp, user_agent);
if (!cs::storeUserData(pp["username"], user_agent, data))
{
BLT_ERROR("Failed to update user data");
return cs::redirect("login.html");
}
session.set("clientID", data.clientID);
session.set("clientToken", data.clientToken);
if (pp.hasKey("remember_me") && pp["remember_me"][0] == 'T')
{
auto& cookie_context = app.get_context<crow::CookieParser>(req);
cookie_context.set_cookie("clientID", data.clientID).path("/").max_age(cookie_age);
cookie_context.set_cookie("clientToken", data.clientToken).path("/").max_age(cookie_age);
}
return cs::redirect(pp.hasKey("referer") ? pp["referer"] : "/");
} else
return cs::redirect("login.html");
}
}

View File

@ -8,29 +8,57 @@
#include <crowsite/utility.h>
#include <crowsite/util/md_to_html.h>
#include <blt/std/logging.h>
#include <crowsite/sql_helper.h>
#include <blt/std/time.h>
namespace cs
{
sql::database* posts_database;
response_info handleProjectPage(const request_info& req)
{
std::string buffer;
buffer += "<html><head></head><body>";
auto htmlData = loadMarkdownAsHTML(cs::fs::createDataFilePath("Billionaire Propaganda.md"));
buffer += htmlData;
buffer += "</body>";
if (req.url_params.contains("post"))
{
BLT_TRACE(req.url_params.at("post"));
sql::statement posts(posts_database, "SELECT file FROM posts WHERE postID=?;");
posts.set(req.url_params.at("post"), 0);
posts.execute();
return {loadMarkdownAsHTML(cs::fs::createDataFilePath(posts.get<std::string>(2)))};
}
return {buffer};
return {""};
}
void posts_init()
{
posts_database = new sql::database(cs::fs::createDataFilePath("db/posts.sqlite"));
sql::auto_statement(
posts_database,
"CREATE TABLE IF NOT EXISTS posts(postID INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT, title TEXT, file TEXT);"
);
sql::auto_statement(
posts_database,
"CREATE TABLE IF NOT EXISTS modifications(postID INTEGER, date TEXT, FOREIGN KEY(postID) REFERENCES posts(postID));"
);
sql::auto_statement(
posts_database,
"CREATE TABLE IF NOT EXISTS tags(postID INTEGER, tag TEXT, FOREIGN KEY(postID) REFERENCES posts(postID));"
);
sql::auto_statement(
posts_database,
"CREATE TABLE IF NOT EXISTS types(postID INTEGER, type INTEGER, FOREIGN KEY(postID) REFERENCES posts(postID));"
);
}
void posts_cleanup()
{
delete posts_database;
}

View File

@ -0,0 +1,69 @@
/*
* Created by Brett on 01/09/23.
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#include <crowsite/site/routing.h>
#include <blt/std/logging.h>
#include "crowsite/util/crow_session_util.h"
#include "crowsite/utility.h"
#include "crowsite/util/crow_conversion.h"
#include "crowsite/site/home.h"
namespace cs
{
inline void createLoginRoutes(CrowApp& app, CacheEngine& engine)
{
CROW_ROUTE(app, "/login.html")(
[&app, &engine](const crow::request& req) -> crow::response {
if (cs::isUserLoggedIn(app, req))
return cs::redirect("/");
return cs::handle_root_page({app, engine, req, "login.html"});
}
);
CROW_ROUTE(app, "/logout.html")(
[&app](const crow::request& req) -> crow::response {
cs::destroyUserSession(app, req);
return cs::redirect("/");
}
);
CROW_ROUTE(app, "/res/login").methods(crow::HTTPMethod::POST)(
[&app](const crow::request& req) {
return cs::handle_login_request(req, app);
}
);
}
void establishHomeRoutes(CrowApp& app, CacheEngine& engine)
{
CROW_ROUTE(app, "/favicon.ico")(
[](crow::response& local_fav_res) {
local_fav_res.compressed = false;
local_fav_res.set_static_file_info_unsafe(cs::fs::createStaticFilePath("images/favicon.ico"));
local_fav_res.set_header("content-type", "image/x-icon");
local_fav_res.end();
}
);
createLoginRoutes(app, engine);
CROW_ROUTE(app, "/<string>")(
[&app, &engine](const crow::request& req, const std::string& name) -> crow::response {
return cs::handle_root_page({app, engine, req, name});
}
);
CROW_ROUTE(app, "/")(
[&engine, &app](const crow::request& req) {
return cs::handle_root_page({app, engine, req, "index.html"});
}
);
}
void establishProjectRoutes(CrowApp& app, CacheEngine& engine)
{
}
}

View File

@ -55,13 +55,13 @@ namespace cs
{
std::string createStaticFilePath(const std::string& file)
{
auto path = std::string(CROWSITE_STATIC_DIRECTORY);
auto path = std::string(CROW_STATIC_DIRECTORY);
if (!path.ends_with('/'))
path += '/';
path += file;
// prevent crow from hanging web responses when we make a typo in the filename
if (!std::filesystem::exists(path))
throw std::runtime_error("Unable to create file path because file does not exist!");
if (!std::filesystem::exists(path.substr(0, path.find_last_of('/'))))
throw std::runtime_error("Unable to create file path because path does not exist!");
return path;
}
@ -72,8 +72,8 @@ namespace cs
path += '/';
path += "webcontent/";
path += file;
if (!std::filesystem::exists(path))
throw std::runtime_error("Unable to create file path because file does not exist!");
if (!std::filesystem::exists(path.substr(0, path.find_last_of('/'))))
throw std::runtime_error("Unable to create file path because folder does not exist!");
return path;
}
@ -84,8 +84,8 @@ namespace cs
path += '/';
path += "data/";
path += file;
if (!std::filesystem::exists(path))
throw std::runtime_error("Unable to create file path because file does not exist!");
if (!std::filesystem::exists(path.substr(0, path.find_last_of('/'))))
throw std::runtime_error("Unable to create file path because folder does not exist!");
return path;
}
}

View File

@ -11,11 +11,7 @@
#include <crowsite/site/posts.h>
#include <crowsite/util/crow_log.h>
#include <crowsite/util/crow_conversion.h>
#define CS_SESSION cs::checkAndUpdateUserSession(app, req); \
auto& session = app.get_context<Session>(req); \
auto s_clientID = session.get("clientID", ""); \
auto s_clientToken = session.get("clientToken", ""); \
#include <crowsite/site/routing.h>
int main(int argc, const char** argv)
{
@ -27,6 +23,7 @@ int main(int argc, const char** argv)
blt::arg_parse parser;
parser.addArgument(blt::arg_builder("--tests").setAction(blt::arg_action_t::STORE_TRUE).build());
parser.addArgument(blt::arg_builder("--standalone").setAction(blt::arg_action_t::STORE_TRUE).build());
parser.addArgument(blt::arg_builder({"--port", "-p"}).setDefault(8080).build());
parser.addArgument(blt::arg_builder("token").setRequired().build());
auto args = parser.parse_args(argc, argv);
@ -39,17 +36,14 @@ int main(int argc, const char** argv)
static BLT_CrowLogger bltCrowLogger{};
crow::logger::setHandler(&bltCrowLogger);
const auto session_age = 24 * 60 * 60;
const auto cookie_age = 180 * 24 * 60 * 60;
BLT_INFO("Init Crow with compression and logging enabled!");
CrowApp app{Session{
// customize cookies
crow::CookieParser::Cookie("session").max_age(session_age).path("/"),
crow::CookieParser::Cookie("session").max_age(cs::session_age).path("/"),
// set session id length (small value only for demonstration purposes)
16,
// init the store
crow::FileStore{std::string(CROWSITE_FILES_PATH) + "/data/session", session_age}}};
crow::FileStore{std::string(CROWSITE_FILES_PATH) + "/data/session", cs::session_age}}};
app.use_compression(crow::compression::GZIP);
app.loglevel(crow::LogLevel::WARNING);
@ -74,73 +68,7 @@ int main(int argc, const char** argv)
BLT_INFO("Creating routes");
CROW_ROUTE(app, "/favicon.ico")(
[](crow::response& local_fav_res) {
local_fav_res.compressed = false;
local_fav_res.set_static_file_info_unsafe(cs::fs::createStaticFilePath("images/favicon.ico"));
local_fav_res.set_header("content-type", "image/x-icon");
local_fav_res.end();
}
);
CROW_ROUTE(app, "/login.html")(
[&app, &engine](const crow::request& req) -> crow::response {
if (cs::isUserLoggedIn(app, req))
return cs::redirect("/");
return cs::handle_root_page({app, engine, req, "login.html"});
}
);
CROW_ROUTE(app, "/logout.html")(
[&app](const crow::request& req) -> crow::response {
cs::destroyUserSession(app, req);
return cs::redirect("/");
}
);
CROW_ROUTE(app, "/<string>")(
[&app, &engine](const crow::request& req, const std::string& name) -> crow::response {
return cs::handle_root_page({app, engine, req, name});
}
);
CROW_ROUTE(app, "/res/login").methods(crow::HTTPMethod::POST)(
[&app](const crow::request& req) {
cs::parser::Post pp(req.body);
auto& session = app.get_context<Session>(req);
std::string user_agent;
for (const auto& h : req.headers)
if (h.first == "User-Agent")
{
user_agent = h.second;
break;
}
// either cs::redirect to clear the form if failed or pass user to index
if (cs::checkUserAuthorization(pp))
{
cs::cookie_data data = cs::createUserAuthTokens(pp, user_agent);
if (!cs::storeUserData(pp["username"], user_agent, data))
{
BLT_ERROR("Failed to update user data");
return cs::redirect("login.html");
}
session.set("clientID", data.clientID);
session.set("clientToken", data.clientToken);
if (pp.hasKey("remember_me") && pp["remember_me"][0] == 'T')
{
auto& cookie_context = app.get_context<crow::CookieParser>(req);
cookie_context.set_cookie("clientID", data.clientID).path("/").max_age(cookie_age);
cookie_context.set_cookie("clientToken", data.clientToken).path("/").max_age(cookie_age);
}
return cs::redirect(pp.hasKey("referer") ? pp["referer"] : "/");
} else
return cs::redirect("login.html");
}
);
cs::establishHomeRoutes(app, engine);
CROW_ROUTE(app, "/projects/<path>")(
[&engine, &app](const crow::request& req, const std::string& path) {
@ -162,12 +90,6 @@ int main(int argc, const char** argv)
}
);
CROW_ROUTE(app, "/")(
[&engine, &app](const crow::request& req) {
return cs::handle_root_page({app, engine, req, "index.html"});
}
);
CROW_CATCHALL_ROUTE(app)(
[&engine]() {
return engine.fetch("default.html");
@ -187,9 +109,27 @@ int main(int argc, const char** argv)
}
}
);
// int flags = fcntl(0, F_GETFL, 0);
// fcntl(0, F_SETFL, flags | O_NONBLOCK);
auto port = blt::arg_parse::get_cast<int32_t>(args["port"]);
BLT_INFO("Starting Crow website on port %d", port);
app.port(port).multithreaded().run();
if (args.contains("standalone"))
{
auto crw = app.port(port).multithreaded().run_async();
std::string line;
while (crw.valid())
{
//std::cin.clear(std::ios::badbit | std::ios::failbit | std::ios::eofbit);
std::getline(std::cin, line);
if (!line.empty())
BLT_TRACE(line);
}
} else
app.port(port).multithreaded().run();
cs::posts_cleanup();