mirror of
https://github.com/KingDuckZ/kamokan.git
synced 2025-06-07 00:51:41 +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();
|
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;
|
tawashi::Escapist houdini;
|
||||||
parContext["pastie"] = houdini.escape_html(parPastie);
|
parContext["pastie"] = houdini.escape_html(parPastie.text);
|
||||||
}
|
}
|
||||||
} //namespace kamokan
|
} //namespace kamokan
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace kamokan {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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 tawashi::HttpHeader on_general_pastie_process() override;
|
||||||
virtual bool is_submit_page() const override { return true; }
|
virtual bool is_submit_page() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "cgi_env.hpp"
|
#include "cgi_env.hpp"
|
||||||
#include "settings_bag.hpp"
|
#include "settings_bag.hpp"
|
||||||
#include "error_reasons.hpp"
|
#include "error_reasons.hpp"
|
||||||
|
#include "spdlog.hpp"
|
||||||
#include "redis_to_error_reason.hpp"
|
#include "redis_to_error_reason.hpp"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
|
@ -45,7 +46,7 @@ namespace kamokan {
|
||||||
|
|
||||||
boost::string_view token = get_search_token(cgi_env());
|
boost::string_view token = get_search_token(cgi_env());
|
||||||
m_pastie_info =
|
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)
|
if (m_pastie_info.error)
|
||||||
return make_error_redirect(redis_to_error_reason(*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_token"] = get_search_token(cgi_env());
|
||||||
parContext["pastie_lang"] = pastie_lang;
|
parContext["pastie_lang"] = pastie_lang;
|
||||||
parContext["colourless"] = pastie_lang.empty() or pastie_lang == "colourless";
|
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 {
|
bool GeneralPastieResponse::token_invalid() const {
|
||||||
|
@ -93,4 +111,8 @@ namespace kamokan {
|
||||||
else
|
else
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::string_view GeneralPastieResponse::requested_lang() const {
|
||||||
|
return boost::string_view();
|
||||||
|
}
|
||||||
} //namespace kamokan
|
} //namespace kamokan
|
||||||
|
|
|
@ -30,14 +30,21 @@ namespace kamokan {
|
||||||
);
|
);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
struct Pastie {
|
||||||
|
std::string text;
|
||||||
|
std::string comment;
|
||||||
|
bool highlighted;
|
||||||
|
};
|
||||||
|
|
||||||
bool pastie_not_found() const;
|
bool pastie_not_found() const;
|
||||||
bool token_invalid() const;
|
bool token_invalid() const;
|
||||||
|
virtual boost::string_view requested_lang() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual tawashi::HttpHeader on_process() override final;
|
virtual tawashi::HttpHeader on_process() override final;
|
||||||
virtual void on_mustache_prepare (mstch::map& parContext) override final;
|
virtual void on_mustache_prepare (mstch::map& parContext) override final;
|
||||||
virtual tawashi::HttpHeader on_general_pastie_process() = 0;
|
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;
|
std::string default_pastie_lang() override;
|
||||||
|
|
||||||
Storage::RetrievedPastie m_pastie_info;
|
Storage::RetrievedPastie m_pastie_info;
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "settings_bag.hpp"
|
#include "settings_bag.hpp"
|
||||||
#include "escapist.hpp"
|
#include "escapist.hpp"
|
||||||
#include "cgi_env.hpp"
|
#include "cgi_env.hpp"
|
||||||
#include "spdlog.hpp"
|
|
||||||
#include "highlight_functions.hpp"
|
#include "highlight_functions.hpp"
|
||||||
#include <ciso646>
|
#include <ciso646>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -70,41 +69,48 @@ namespace kamokan {
|
||||||
m_plain_text(false),
|
m_plain_text(false),
|
||||||
m_syntax_highlight(true)
|
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() {
|
tawashi::HttpHeader PastieResponse::on_general_pastie_process() {
|
||||||
auto get = cgi_env().query_string_split();
|
if (m_plain_text)
|
||||||
const std::string& query_str(cgi_env().query_string());
|
|
||||||
if (get["m"] == "plain" or query_str.empty()) {
|
|
||||||
m_plain_text = true;
|
|
||||||
return tawashi::make_header_type_text_utf8();
|
return tawashi::make_header_type_text_utf8();
|
||||||
}
|
else
|
||||||
else if (query_str == g_nolang_token) {
|
return tawashi::make_header_type_html();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 processed_pastie;
|
||||||
std::string highlight_comment;
|
std::string highlight_comment;
|
||||||
if (m_syntax_highlight) {
|
if (m_syntax_highlight) {
|
||||||
processed_pastie = std::move(parPastie);
|
processed_pastie = std::move(parPastie.text);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
assert(not parPastie.highlighted);
|
||||||
tawashi::Escapist houdini;
|
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) {
|
if (not m_plain_text and m_syntax_highlight) {
|
||||||
SplitHighlightedPastie split = highlight_string(std::move(processed_pastie), m_pastie_lang, settings());
|
if (parPastie.highlighted) {
|
||||||
processed_pastie = std::move(split.text);
|
assert(not parPastie.comment.empty());
|
||||||
highlight_comment = std::move(split.comment);
|
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);
|
parContext["pastie"] = std::move(processed_pastie);
|
||||||
|
@ -121,4 +127,8 @@ namespace kamokan {
|
||||||
else
|
else
|
||||||
return load_mustache();
|
return load_mustache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::string_view PastieResponse::requested_lang() const {
|
||||||
|
return m_pastie_lang;
|
||||||
|
}
|
||||||
} //namespace kamokan
|
} //namespace kamokan
|
||||||
|
|
|
@ -32,11 +32,12 @@ namespace kamokan {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual boost::string_view page_basename() const override { return boost::string_view("pastie"); }
|
virtual boost::string_view page_basename() const override { return boost::string_view("pastie"); }
|
||||||
|
virtual boost::string_view requested_lang() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual std::string on_mustache_retrieve() override;
|
virtual std::string on_mustache_retrieve() override;
|
||||||
virtual tawashi::HttpHeader on_general_pastie_process() 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; }
|
virtual bool is_pastie_page() const override { return true; }
|
||||||
|
|
||||||
std::string m_pastie_lang;
|
std::string m_pastie_lang;
|
||||||
|
|
|
@ -1,14 +1,33 @@
|
||||||
local full_token = KEYS[1]
|
local full_token = KEYS[1]
|
||||||
local result = redis.call("HMGET", full_token, "pastie", "selfdes", "lang")
|
local requested_lang = ARGV[1]
|
||||||
if false == result[1] then
|
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")
|
return redis.error_reply("PastieNotFound")
|
||||||
end
|
end
|
||||||
|
|
||||||
local selfdes = 0
|
local selfdes = 0
|
||||||
local deleted = 0
|
local deleted = 0
|
||||||
if result[2] == "1" then
|
if pastie_selfdes == "1" then
|
||||||
deleted = redis.call("DEL", full_token)
|
deleted = redis.call("DEL", full_token)
|
||||||
selfdes = 1
|
selfdes = 1
|
||||||
end
|
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
|
} //unnamed namespace
|
||||||
|
|
||||||
Storage::RetrievedPastie::RetrievedPastie() :
|
Storage::RetrievedPastie::RetrievedPastie() :
|
||||||
pastie(),
|
highlighted(false),
|
||||||
lang(),
|
|
||||||
self_destructed(false),
|
self_destructed(false),
|
||||||
valid_token(false)
|
valid_token(false)
|
||||||
{
|
{
|
||||||
|
@ -187,9 +186,15 @@ namespace kamokan {
|
||||||
return make_submission_result(std::move(token));
|
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;
|
using boost::string_view;
|
||||||
|
|
||||||
|
|
||||||
RetrievedPastie retval;
|
RetrievedPastie retval;
|
||||||
retval.valid_token = is_valid_token(parToken, parMaxTokenLen);
|
retval.valid_token = is_valid_token(parToken, parMaxTokenLen);
|
||||||
if (not retval.valid_token)
|
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));
|
redis::Script retrieve = m_redis->command().make_script(string_view(g_load_script, g_load_script_size));
|
||||||
auto batch = m_redis->command().make_batch();
|
auto batch = m_redis->command().make_batch();
|
||||||
std::string token_with_prefix = make_regular_pastie_token(parToken);
|
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();
|
auto raw_replies = batch.replies();
|
||||||
if (raw_replies.empty())
|
if (raw_replies.empty())
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -213,8 +222,10 @@ namespace kamokan {
|
||||||
retval.pastie = get_string(pastie_reply[0]);
|
retval.pastie = get_string(pastie_reply[0]);
|
||||||
const redis::RedisInt selfdes = get_integer(pastie_reply[1]);
|
const redis::RedisInt selfdes = get_integer(pastie_reply[1]);
|
||||||
const redis::RedisInt deleted = get_integer(pastie_reply[2]);
|
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.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) {
|
if (selfdes and not deleted) {
|
||||||
auto statuslog = spdlog::get("statuslog");
|
auto statuslog = spdlog::get("statuslog");
|
||||||
|
|
|
@ -47,6 +47,8 @@ namespace kamokan {
|
||||||
boost::optional<std::string> pastie;
|
boost::optional<std::string> pastie;
|
||||||
boost::optional<std::string> lang;
|
boost::optional<std::string> lang;
|
||||||
boost::optional<std::string> error;
|
boost::optional<std::string> error;
|
||||||
|
boost::optional<std::string> comment;
|
||||||
|
bool highlighted;
|
||||||
bool self_destructed;
|
bool self_destructed;
|
||||||
bool valid_token;
|
bool valid_token;
|
||||||
};
|
};
|
||||||
|
@ -71,7 +73,11 @@ namespace kamokan {
|
||||||
uint32_t parMaxTokenLen
|
uint32_t parMaxTokenLen
|
||||||
) const;
|
) 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)
|
#if defined(KAMOKAN_WITH_TESTING)
|
||||||
const SettingsBag& settings() const;
|
const SettingsBag& settings() const;
|
||||||
|
|
|
@ -62,7 +62,11 @@ namespace kamokan {
|
||||||
return submission_res;
|
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(
|
auto it_found = std::find_if(
|
||||||
m_submitted_pasties.begin(),
|
m_submitted_pasties.begin(),
|
||||||
m_submitted_pasties.end(),
|
m_submitted_pasties.end(),
|
||||||
|
|
|
@ -52,7 +52,11 @@ namespace kamokan {
|
||||||
const std::string& parRemoteIP
|
const std::string& parRemoteIP
|
||||||
) const override;
|
) 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;
|
const std::vector<SubmittedPastie>& submitted_pasties() const;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue