cache refinement
parent
2f4b2a8c98
commit
4baf70ad0c
|
@ -8,8 +8,8 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <blt/std/hashmap.h>
|
#include <blt/std/hashmap.h>
|
||||||
|
|
||||||
#define CROW_STATIC_DIRECTORY "/mnt/games/Projects/cpp/crowsite/crow_test/static/"
|
#define CROW_STATIC_DIRECTORY "/home/brett/projects/cpp/crowsite/crow_test/static/"
|
||||||
#define SITE_FILES_PATH "/mnt/games/Projects/cpp/crowsite/crow_test"
|
#define SITE_FILES_PATH "/home/brett/projects/cpp/crowsite/crow_test"
|
||||||
#define CROW_STATIC_ENDPOINT "/static/<path>"
|
#define CROW_STATIC_ENDPOINT "/static/<path>"
|
||||||
|
|
||||||
#define MILES_SITE
|
#define MILES_SITE
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
namespace cs {
|
namespace cs {
|
||||||
|
|
||||||
|
class LexerSyntaxError : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
LexerSyntaxError(): std::runtime_error("Invalid template syntax. EOF occurred before template was fully processed!"){}
|
||||||
|
};
|
||||||
|
|
||||||
constexpr uint64_t toMB = 1024 * 1024;
|
constexpr uint64_t toMB = 1024 * 1024;
|
||||||
|
|
||||||
struct CacheSettings {
|
struct CacheSettings {
|
||||||
|
|
|
@ -12,52 +12,6 @@
|
||||||
|
|
||||||
namespace cs {
|
namespace cs {
|
||||||
|
|
||||||
struct StringLexer
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
std::string str;
|
|
||||||
size_t index = 0;
|
|
||||||
public:
|
|
||||||
explicit StringLexer(std::string str): str(std::move(str))
|
|
||||||
{}
|
|
||||||
|
|
||||||
inline bool hasNext()
|
|
||||||
{
|
|
||||||
if (index >= str.size())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool hasTemplatePrefix(char c)
|
|
||||||
{
|
|
||||||
if (index + 2 >= str.size())
|
|
||||||
return false;
|
|
||||||
return str[index] == '{' && str[index + 1] == '{' && str[index + 2] == c;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool hasTemplateSuffix()
|
|
||||||
{
|
|
||||||
if (index + 1 >= str.size())
|
|
||||||
return false;
|
|
||||||
return str[index] == '}' && str[index + 1] == '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void consumeTemplatePrefix()
|
|
||||||
{
|
|
||||||
index += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void consumeTemplateSuffix()
|
|
||||||
{
|
|
||||||
index += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline char consume()
|
|
||||||
{
|
|
||||||
return str[index++];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class StaticContext {
|
class StaticContext {
|
||||||
private:
|
private:
|
||||||
HASHMAP<std::string, std::string> replacements;
|
HASHMAP<std::string, std::string> replacements;
|
||||||
|
@ -82,16 +36,6 @@ namespace cs {
|
||||||
explicit HTMLPage(std::string siteData);
|
explicit HTMLPage(std::string siteData);
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<HTMLPage> load(const std::string& path);
|
static std::unique_ptr<HTMLPage> load(const std::string& path);
|
||||||
/**
|
|
||||||
* Attempts to resolve linked resources like CSS and JS in order to speedup page loading.
|
|
||||||
*/
|
|
||||||
void resolveResources();
|
|
||||||
/**
|
|
||||||
* Uses the static context provided to resolve known variables before user requests
|
|
||||||
* @param context context to use
|
|
||||||
* @return string containing resolved static templates
|
|
||||||
*/
|
|
||||||
std::string render(StaticContext& context);
|
|
||||||
|
|
||||||
inline std::string& getRawSite() {
|
inline std::string& getRawSite() {
|
||||||
return m_SiteData;
|
return m_SiteData;
|
||||||
|
|
|
@ -10,6 +10,72 @@
|
||||||
|
|
||||||
namespace cs
|
namespace cs
|
||||||
{
|
{
|
||||||
|
struct StringLexer
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string str;
|
||||||
|
size_t index = 0;
|
||||||
|
public:
|
||||||
|
explicit StringLexer(std::string str): str(std::move(str))
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline bool hasNext()
|
||||||
|
{
|
||||||
|
if (index >= str.size())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool hasTemplatePrefix(char c)
|
||||||
|
{
|
||||||
|
if (index + 2 >= str.size())
|
||||||
|
return false;
|
||||||
|
return str[index] == '{' && str[index + 1] == '{' && str[index + 2] == c;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool hasTemplateSuffix()
|
||||||
|
{
|
||||||
|
if (index + 1 >= str.size())
|
||||||
|
return false;
|
||||||
|
return str[index] == '}' && str[index + 1] == '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void consumeTemplatePrefix()
|
||||||
|
{
|
||||||
|
// because any custom mustache syntax will have to have a prefix like '$' or '@'
|
||||||
|
// it is fine that we make the assumption of 3 characters consumed.
|
||||||
|
index += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void consumeTemplateSuffix()
|
||||||
|
{
|
||||||
|
index += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function assumes hasTemplatePrefix(char) has returned true and will consume both the prefix and suffix
|
||||||
|
* @return the token found between the prefix and suffix
|
||||||
|
* @throws LexerSyntaxError if the parser is unable to process a full token
|
||||||
|
*/
|
||||||
|
inline std::string consumeToken(){
|
||||||
|
consumeTemplatePrefix();
|
||||||
|
std::string token;
|
||||||
|
while (!hasTemplateSuffix()) {
|
||||||
|
if (!hasNext()) {
|
||||||
|
throw LexerSyntaxError();
|
||||||
|
}
|
||||||
|
token += consume();
|
||||||
|
}
|
||||||
|
consumeTemplateSuffix();
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char consume()
|
||||||
|
{
|
||||||
|
return str[index++];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
double toSeconds(uint64_t v)
|
double toSeconds(uint64_t v)
|
||||||
{
|
{
|
||||||
|
@ -92,7 +158,7 @@ namespace cs
|
||||||
auto fullPath = cs::fs::createWebFilePath(path);
|
auto fullPath = cs::fs::createWebFilePath(path);
|
||||||
auto page = HTMLPage::load(fullPath);
|
auto page = HTMLPage::load(fullPath);
|
||||||
resolveLinks(path, *page);
|
resolveLinks(path, *page);
|
||||||
auto renderedPage = page->render(m_Context);
|
const auto& renderedPage = page->getRawSite();
|
||||||
m_Pages[path] = CacheValue{
|
m_Pages[path] = CacheValue{
|
||||||
blt::system::getCurrentTimeNanoseconds(),
|
blt::system::getCurrentTimeNanoseconds(),
|
||||||
std::filesystem::last_write_time(fullPath),
|
std::filesystem::last_write_time(fullPath),
|
||||||
|
@ -152,28 +218,36 @@ namespace cs
|
||||||
{
|
{
|
||||||
if (lexer.hasTemplatePrefix('@'))
|
if (lexer.hasTemplatePrefix('@'))
|
||||||
{
|
{
|
||||||
lexer.consumeTemplatePrefix();
|
auto token = lexer.consumeToken();
|
||||||
std::string token;
|
for (const auto& suffix : valid_file_endings)
|
||||||
while (!lexer.hasTemplateSuffix()) {
|
{
|
||||||
if (!lexer.hasNext()) {
|
if (token.ends_with(suffix))
|
||||||
BLT_WARN("Invalid template syntax. EOF occurred before template was fully processed!");
|
{
|
||||||
break;
|
if (token == file)
|
||||||
}
|
{
|
||||||
token += lexer.consume();
|
|
||||||
}
|
|
||||||
lexer.consumeTemplateSuffix();
|
|
||||||
for (const auto& suffix : valid_file_endings){
|
|
||||||
if (token.ends_with(suffix)) {
|
|
||||||
auto path = cs::fs::createWebFilePath(token);
|
|
||||||
if (path == file){
|
|
||||||
BLT_WARN("Recursive load detected!");
|
BLT_WARN("Recursive load detected!");
|
||||||
BLT_WARN("Caching Engine will ignore this attempt, however, it is recommended that you remove the recursive call.");
|
BLT_WARN("Caching Engine will ignore this, however, it is recommended that you remove the recursive call.");
|
||||||
BLT_WARN("Detected in file '%s' offending link '%s'", file.c_str(), token.c_str());
|
BLT_WARN("Detected in file '%s' offending link '%s'", file.c_str(), token.c_str());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
resolvedSite += fetch(path);
|
resolvedSite += fetch(token);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (lexer.hasTemplatePrefix('$'))
|
||||||
|
{
|
||||||
|
auto token = lexer.consumeToken();
|
||||||
|
if (std::find_if(
|
||||||
|
m_Context.begin(), m_Context.end(),
|
||||||
|
[&token](auto in) -> bool {
|
||||||
|
return token == in.first;
|
||||||
|
}
|
||||||
|
) == m_Context.end())
|
||||||
|
{
|
||||||
|
// unable to find the token, we should throw an error to tell the user! (or admin in this case)
|
||||||
|
BLT_WARN("Unable to find token '%s'!", token.c_str());
|
||||||
|
} else
|
||||||
|
resolvedSite += m_Context[token];
|
||||||
} else
|
} else
|
||||||
resolvedSite += lexer.consume();
|
resolvedSite += lexer.consume();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,35 +13,6 @@
|
||||||
namespace cs
|
namespace cs
|
||||||
{
|
{
|
||||||
|
|
||||||
class LexerSyntaxException : public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit LexerSyntaxException(const std::string& token):
|
|
||||||
std::runtime_error(
|
|
||||||
"Extended-mustache syntax error! An opening '{{' must be closed by '}}'! (near: '" +
|
|
||||||
token + "')"
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
class LexerException : public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit LexerException(const std::string& message):
|
|
||||||
std::runtime_error("Extended-mustache syntax processing error! " + message)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SyntaxException : public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit SyntaxException():
|
|
||||||
std::runtime_error(
|
|
||||||
"Extended-mustache syntax error! Static context keys should not contain $"
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<HTMLPage> HTMLPage::load(const std::string& path)
|
std::unique_ptr<HTMLPage> HTMLPage::load(const std::string& path)
|
||||||
{
|
{
|
||||||
std::string htmlSource;
|
std::string htmlSource;
|
||||||
|
@ -72,51 +43,4 @@ namespace cs
|
||||||
|
|
||||||
HTMLPage::HTMLPage(std::string siteData): m_SiteData(std::move(siteData))
|
HTMLPage::HTMLPage(std::string siteData): m_SiteData(std::move(siteData))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string HTMLPage::render(StaticContext& context)
|
|
||||||
{
|
|
||||||
std::string processedSiteData = m_SiteData;
|
|
||||||
|
|
||||||
std::string buffer;
|
|
||||||
|
|
||||||
StringLexer lexer(processedSiteData);
|
|
||||||
|
|
||||||
while (lexer.hasNext())
|
|
||||||
{
|
|
||||||
if (lexer.hasTemplatePrefix('$'))
|
|
||||||
{
|
|
||||||
lexer.consumeTemplatePrefix();
|
|
||||||
std::string token;
|
|
||||||
while (!lexer.hasTemplateSuffix())
|
|
||||||
{
|
|
||||||
if (!lexer.hasNext())
|
|
||||||
{
|
|
||||||
BLT_FATAL("Invalid template syntax. EOF occurred before template was fully processed!");
|
|
||||||
throw LexerSyntaxException(token);
|
|
||||||
}
|
|
||||||
token += lexer.consume();
|
|
||||||
}
|
|
||||||
lexer.consumeTemplateSuffix();
|
|
||||||
if (std::find_if(
|
|
||||||
context.begin(), context.end(),
|
|
||||||
[&token](auto in) -> bool {
|
|
||||||
return token == in.first;
|
|
||||||
}
|
|
||||||
) == context.end())
|
|
||||||
{
|
|
||||||
// unable to find the token, we should throw an error to tell the user! (or admin in this case)
|
|
||||||
BLT_WARN("Unable to find token '%s'!", token.c_str());
|
|
||||||
} else
|
|
||||||
buffer += context[token];
|
|
||||||
} else
|
|
||||||
buffer += lexer.consume();
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HTMLPage::resolveResources()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,8 @@ crow::response handle_root_page(const site_params& params)
|
||||||
if (cs::isUserLoggedIn(s_clientID, s_clientToken))
|
if (cs::isUserLoggedIn(s_clientID, s_clientToken))
|
||||||
{
|
{
|
||||||
ctx["_logged_in"] = true;
|
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
|
// we don't want to pass all get parameters to the context to prevent leaking information
|
||||||
|
|
Loading…
Reference in New Issue