mirror of
https://github.com/KingDuckZ/kamokan.git
synced 2024-11-23 00:33:44 +00:00
Get the pre-cached highlighted pastie if available.
This commit is contained in:
parent
5b33417979
commit
b7a5ce09e1
11 changed files with 129 additions and 40 deletions
|
@ -32,8 +32,13 @@ namespace kamokan {
|
|||
return tawashi::make_header_type_html();
|
||||
}
|
||||
|
||||
void EditResponse::on_general_mustache_prepare (std::string&& parPastie, mstch::map& parContext) {
|
||||
void EditResponse::on_general_mustache_prepare (
|
||||
GeneralPastieResponse::Pastie&& parPastie,
|
||||
mstch::map& parContext
|
||||
) {
|
||||
assert(not parPastie.highlighted);
|
||||
assert(parPastie.comment.empty());
|
||||
tawashi::Escapist houdini;
|
||||
parContext["pastie"] = houdini.escape_html(parPastie);
|
||||
parContext["pastie"] = houdini.escape_html(parPastie.text);
|
||||
}
|
||||
} //namespace kamokan
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace kamokan {
|
|||
}
|
||||
|
||||
private:
|
||||
virtual void on_general_mustache_prepare (std::string&& parPastie, mstch::map& parContext) override;
|
||||
virtual void on_general_mustache_prepare (GeneralPastieResponse::Pastie&& parPastie, mstch::map& parContext) override;
|
||||
virtual tawashi::HttpHeader on_general_pastie_process() override;
|
||||
virtual bool is_submit_page() const override { return true; }
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "cgi_env.hpp"
|
||||
#include "settings_bag.hpp"
|
||||
#include "error_reasons.hpp"
|
||||
#include "spdlog.hpp"
|
||||
#include "redis_to_error_reason.hpp"
|
||||
#include <cassert>
|
||||
#include <ciso646>
|
||||
|
@ -45,7 +46,7 @@ namespace kamokan {
|
|||
|
||||
boost::string_view token = get_search_token(cgi_env());
|
||||
m_pastie_info =
|
||||
storage().retrieve_pastie(token, settings().as<uint32_t>("max_token_length"));
|
||||
storage().retrieve_pastie(token, settings().as<uint32_t>("max_token_length"), this->requested_lang());
|
||||
|
||||
if (m_pastie_info.error)
|
||||
return make_error_redirect(redis_to_error_reason(*m_pastie_info.error));
|
||||
|
@ -74,8 +75,25 @@ namespace kamokan {
|
|||
parContext["pastie_token"] = get_search_token(cgi_env());
|
||||
parContext["pastie_lang"] = pastie_lang;
|
||||
parContext["colourless"] = pastie_lang.empty() or pastie_lang == "colourless";
|
||||
parContext["from_cache"] = m_pastie_info.highlighted;
|
||||
|
||||
this->on_general_mustache_prepare(std::move(*m_pastie_info.pastie), parContext);
|
||||
auto statuslog = spdlog::get("statuslog");
|
||||
SPDLOG_TRACE(
|
||||
statuslog,
|
||||
"General mustache response prepared; pastie len={}, comment len={}, highlighted={}",
|
||||
m_pastie_info.pastie->size(),
|
||||
(m_pastie_info.comment ? m_pastie_info.comment->size() : 0),
|
||||
m_pastie_info.highlighted
|
||||
);
|
||||
|
||||
this->on_general_mustache_prepare(
|
||||
Pastie{
|
||||
std::move(*m_pastie_info.pastie),
|
||||
(m_pastie_info.comment ? std::move(*m_pastie_info.comment) : std::string()),
|
||||
m_pastie_info.highlighted
|
||||
},
|
||||
parContext
|
||||
);
|
||||
}
|
||||
|
||||
bool GeneralPastieResponse::token_invalid() const {
|
||||
|
@ -93,4 +111,8 @@ namespace kamokan {
|
|||
else
|
||||
return std::string();
|
||||
}
|
||||
|
||||
boost::string_view GeneralPastieResponse::requested_lang() const {
|
||||
return boost::string_view();
|
||||
}
|
||||
} //namespace kamokan
|
||||
|
|
|
@ -30,14 +30,21 @@ namespace kamokan {
|
|||
);
|
||||
|
||||
protected:
|
||||
struct Pastie {
|
||||
std::string text;
|
||||
std::string comment;
|
||||
bool highlighted;
|
||||
};
|
||||
|
||||
bool pastie_not_found() const;
|
||||
bool token_invalid() const;
|
||||
virtual boost::string_view requested_lang() const;
|
||||
|
||||
private:
|
||||
virtual tawashi::HttpHeader on_process() override final;
|
||||
virtual void on_mustache_prepare (mstch::map& parContext) override final;
|
||||
virtual tawashi::HttpHeader on_general_pastie_process() = 0;
|
||||
virtual void on_general_mustache_prepare (std::string&& parPastie, mstch::map& parContext) = 0;
|
||||
virtual void on_general_mustache_prepare (Pastie&& parPastie, mstch::map& parContext) = 0;
|
||||
std::string default_pastie_lang() override;
|
||||
|
||||
Storage::RetrievedPastie m_pastie_info;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "settings_bag.hpp"
|
||||
#include "escapist.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include "spdlog.hpp"
|
||||
#include "highlight_functions.hpp"
|
||||
#include <ciso646>
|
||||
#include <algorithm>
|
||||
|
@ -70,41 +69,48 @@ namespace kamokan {
|
|||
m_plain_text(false),
|
||||
m_syntax_highlight(true)
|
||||
{
|
||||
auto get = cgi_env().query_string_split();
|
||||
const std::string& query_str(cgi_env().query_string());
|
||||
if (get["m"] == "plain" or query_str.empty())
|
||||
m_plain_text = true;
|
||||
else if (query_str == g_nolang_token)
|
||||
m_syntax_highlight = false;
|
||||
else if (not query_str.empty())
|
||||
m_pastie_lang = query_str;
|
||||
}
|
||||
|
||||
tawashi::HttpHeader PastieResponse::on_general_pastie_process() {
|
||||
auto get = cgi_env().query_string_split();
|
||||
const std::string& query_str(cgi_env().query_string());
|
||||
if (get["m"] == "plain" or query_str.empty()) {
|
||||
m_plain_text = true;
|
||||
if (m_plain_text)
|
||||
return tawashi::make_header_type_text_utf8();
|
||||
}
|
||||
else if (query_str == g_nolang_token) {
|
||||
m_syntax_highlight = false;
|
||||
}
|
||||
else {
|
||||
m_pastie_lang.clear();
|
||||
if (not query_str.empty())
|
||||
m_pastie_lang = query_str;
|
||||
}
|
||||
return tawashi::make_header_type_html();
|
||||
else
|
||||
return tawashi::make_header_type_html();
|
||||
}
|
||||
|
||||
void PastieResponse::on_general_mustache_prepare (std::string&& parPastie, mstch::map& parContext) {
|
||||
void PastieResponse::on_general_mustache_prepare (
|
||||
GeneralPastieResponse::Pastie&& parPastie,
|
||||
mstch::map& parContext
|
||||
) {
|
||||
std::string processed_pastie;
|
||||
std::string highlight_comment;
|
||||
if (m_syntax_highlight) {
|
||||
processed_pastie = std::move(parPastie);
|
||||
processed_pastie = std::move(parPastie.text);
|
||||
}
|
||||
else {
|
||||
assert(not parPastie.highlighted);
|
||||
tawashi::Escapist houdini;
|
||||
processed_pastie = houdini.escape_html(parPastie);
|
||||
processed_pastie = houdini.escape_html(parPastie.text);
|
||||
}
|
||||
|
||||
if (not m_plain_text and m_syntax_highlight) {
|
||||
SplitHighlightedPastie split = highlight_string(std::move(processed_pastie), m_pastie_lang, settings());
|
||||
processed_pastie = std::move(split.text);
|
||||
highlight_comment = std::move(split.comment);
|
||||
if (parPastie.highlighted) {
|
||||
assert(not parPastie.comment.empty());
|
||||
highlight_comment = std::move(parPastie.comment);
|
||||
}
|
||||
else {
|
||||
SplitHighlightedPastie split = highlight_string(std::move(processed_pastie), requested_lang(), settings());
|
||||
processed_pastie = std::move(split.text);
|
||||
highlight_comment = std::move(split.comment);
|
||||
}
|
||||
}
|
||||
|
||||
parContext["pastie"] = std::move(processed_pastie);
|
||||
|
@ -121,4 +127,8 @@ namespace kamokan {
|
|||
else
|
||||
return load_mustache();
|
||||
}
|
||||
|
||||
boost::string_view PastieResponse::requested_lang() const {
|
||||
return m_pastie_lang;
|
||||
}
|
||||
} //namespace kamokan
|
||||
|
|
|
@ -32,11 +32,12 @@ namespace kamokan {
|
|||
|
||||
protected:
|
||||
virtual boost::string_view page_basename() const override { return boost::string_view("pastie"); }
|
||||
virtual boost::string_view requested_lang() const override;
|
||||
|
||||
private:
|
||||
virtual std::string on_mustache_retrieve() override;
|
||||
virtual tawashi::HttpHeader on_general_pastie_process() override;
|
||||
virtual void on_general_mustache_prepare (std::string&& parPastie, mstch::map& parContext) override;
|
||||
virtual void on_general_mustache_prepare (GeneralPastieResponse::Pastie&& parPastie, mstch::map& parContext) override;
|
||||
virtual bool is_pastie_page() const override { return true; }
|
||||
|
||||
std::string m_pastie_lang;
|
||||
|
|
|
@ -1,14 +1,33 @@
|
|||
local full_token = KEYS[1]
|
||||
local result = redis.call("HMGET", full_token, "pastie", "selfdes", "lang")
|
||||
if false == result[1] then
|
||||
local requested_lang = ARGV[1]
|
||||
local pastie_info = redis.call("HMGET", full_token, "lang", "selfdes")
|
||||
local pastie_lang = pastie_info[1]
|
||||
local pastie_selfdes = pastie_info[2]
|
||||
local ret_pastie = false
|
||||
local ret_comment = ""
|
||||
local is_highlighted = 0
|
||||
if pastie_lang == requested_lang then
|
||||
local result = redis.call("HMGET", full_token, "hl_pastie", "hl_comment")
|
||||
ret_pastie = result[1]
|
||||
ret_comment = result[2]
|
||||
is_highlighted = 1
|
||||
end
|
||||
|
||||
if false == ret_pastie then
|
||||
local result = redis.call("HMGET", full_token, "pastie")
|
||||
ret_pastie = result[1]
|
||||
is_highlighted = 0
|
||||
end
|
||||
|
||||
if false == ret_pastie then
|
||||
return redis.error_reply("PastieNotFound")
|
||||
end
|
||||
|
||||
local selfdes = 0
|
||||
local deleted = 0
|
||||
if result[2] == "1" then
|
||||
if pastie_selfdes == "1" then
|
||||
deleted = redis.call("DEL", full_token)
|
||||
selfdes = 1
|
||||
end
|
||||
|
||||
return {result[1], selfdes, deleted, result[3]}
|
||||
return {ret_pastie, selfdes, deleted, is_highlighted, pastie_lang, ret_comment}
|
||||
|
|
|
@ -92,8 +92,7 @@ namespace kamokan {
|
|||
} //unnamed namespace
|
||||
|
||||
Storage::RetrievedPastie::RetrievedPastie() :
|
||||
pastie(),
|
||||
lang(),
|
||||
highlighted(false),
|
||||
self_destructed(false),
|
||||
valid_token(false)
|
||||
{
|
||||
|
@ -187,9 +186,15 @@ namespace kamokan {
|
|||
return make_submission_result(std::move(token));
|
||||
}
|
||||
|
||||
auto Storage::retrieve_pastie (const boost::string_view& parToken, uint32_t parMaxTokenLen) const -> RetrievedPastie {
|
||||
auto Storage::retrieve_pastie (
|
||||
const boost::string_view& parToken,
|
||||
uint32_t parMaxTokenLen,
|
||||
const boost::string_view& parRequestedLang
|
||||
) const -> RetrievedPastie {
|
||||
|
||||
using boost::string_view;
|
||||
|
||||
|
||||
RetrievedPastie retval;
|
||||
retval.valid_token = is_valid_token(parToken, parMaxTokenLen);
|
||||
if (not retval.valid_token)
|
||||
|
@ -198,7 +203,11 @@ namespace kamokan {
|
|||
redis::Script retrieve = m_redis->command().make_script(string_view(g_load_script, g_load_script_size));
|
||||
auto batch = m_redis->command().make_batch();
|
||||
std::string token_with_prefix = make_regular_pastie_token(parToken);
|
||||
retrieve.run(batch, std::make_tuple(token_with_prefix), std::tuple<>());
|
||||
retrieve.run(
|
||||
batch,
|
||||
std::make_tuple(token_with_prefix),
|
||||
std::make_tuple(parRequestedLang)
|
||||
);
|
||||
auto raw_replies = batch.replies();
|
||||
if (raw_replies.empty())
|
||||
return retval;
|
||||
|
@ -213,8 +222,10 @@ namespace kamokan {
|
|||
retval.pastie = get_string(pastie_reply[0]);
|
||||
const redis::RedisInt selfdes = get_integer(pastie_reply[1]);
|
||||
const redis::RedisInt deleted = get_integer(pastie_reply[2]);
|
||||
retval.lang = get_string(pastie_reply[3]);
|
||||
retval.lang = get_string(pastie_reply[4]);
|
||||
retval.self_destructed = selfdes and deleted;
|
||||
retval.highlighted = static_cast<bool>(get_integer(pastie_reply[3]));
|
||||
retval.comment = get_string(pastie_reply[5]);
|
||||
|
||||
if (selfdes and not deleted) {
|
||||
auto statuslog = spdlog::get("statuslog");
|
||||
|
|
|
@ -47,6 +47,8 @@ namespace kamokan {
|
|||
boost::optional<std::string> pastie;
|
||||
boost::optional<std::string> lang;
|
||||
boost::optional<std::string> error;
|
||||
boost::optional<std::string> comment;
|
||||
bool highlighted;
|
||||
bool self_destructed;
|
||||
bool valid_token;
|
||||
};
|
||||
|
@ -71,7 +73,11 @@ namespace kamokan {
|
|||
uint32_t parMaxTokenLen
|
||||
) const;
|
||||
|
||||
kamokan_virtual_testing RetrievedPastie retrieve_pastie (const boost::string_view& parToken, uint32_t parMaxTokenLen) const;
|
||||
kamokan_virtual_testing RetrievedPastie retrieve_pastie (
|
||||
const boost::string_view& parToken,
|
||||
uint32_t parMaxTokenLen,
|
||||
const boost::string_view& parRequestedLang
|
||||
) const;
|
||||
|
||||
#if defined(KAMOKAN_WITH_TESTING)
|
||||
const SettingsBag& settings() const;
|
||||
|
|
|
@ -62,7 +62,11 @@ namespace kamokan {
|
|||
return submission_res;
|
||||
}
|
||||
|
||||
Storage::RetrievedPastie FakeStorage::retrieve_pastie (const boost::string_view& parToken, uint32_t parMaxTokenLen) const {
|
||||
Storage::RetrievedPastie FakeStorage::retrieve_pastie (
|
||||
const boost::string_view& parToken,
|
||||
uint32_t parMaxTokenLen,
|
||||
const boost::string_view& parLang
|
||||
) const {
|
||||
auto it_found = std::find_if(
|
||||
m_submitted_pasties.begin(),
|
||||
m_submitted_pasties.end(),
|
||||
|
|
|
@ -52,7 +52,11 @@ namespace kamokan {
|
|||
const std::string& parRemoteIP
|
||||
) const override;
|
||||
|
||||
kamokan_virtual_testing Storage::RetrievedPastie retrieve_pastie (const boost::string_view& parToken, uint32_t parMaxTokenLen) const override;
|
||||
kamokan_virtual_testing Storage::RetrievedPastie retrieve_pastie (
|
||||
const boost::string_view& parToken,
|
||||
uint32_t parMaxTokenLen,
|
||||
const boost::string_view& parLang
|
||||
) const override;
|
||||
|
||||
const std::vector<SubmittedPastie>& submitted_pasties() const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue