From b7a5ce09e14bf640a518d32616839023bd8641d8 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Tue, 8 Aug 2017 00:09:03 +0100 Subject: [PATCH] Get the pre-cached highlighted pastie if available. --- src/kamokan_impl/edit_response.cpp | 9 +++- src/kamokan_impl/edit_response.hpp | 2 +- src/kamokan_impl/general_pastie_response.cpp | 26 +++++++++- src/kamokan_impl/general_pastie_response.hpp | 9 +++- src/kamokan_impl/pastie_response.cpp | 52 ++++++++++++-------- src/kamokan_impl/pastie_response.hpp | 3 +- src/kamokan_impl/retrieve_pastie.lua | 27 ++++++++-- src/kamokan_impl/storage.cpp | 21 ++++++-- src/kamokan_impl/storage.hpp | 8 ++- test/simulation/fake_storage.cpp | 6 ++- test/simulation/fake_storage.hpp | 6 ++- 11 files changed, 129 insertions(+), 40 deletions(-) diff --git a/src/kamokan_impl/edit_response.cpp b/src/kamokan_impl/edit_response.cpp index 6ea343c..2fa5986 100644 --- a/src/kamokan_impl/edit_response.cpp +++ b/src/kamokan_impl/edit_response.cpp @@ -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 diff --git a/src/kamokan_impl/edit_response.hpp b/src/kamokan_impl/edit_response.hpp index 0ec19af..e4ec2bb 100644 --- a/src/kamokan_impl/edit_response.hpp +++ b/src/kamokan_impl/edit_response.hpp @@ -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; } }; diff --git a/src/kamokan_impl/general_pastie_response.cpp b/src/kamokan_impl/general_pastie_response.cpp index ed2cc57..46976bf 100644 --- a/src/kamokan_impl/general_pastie_response.cpp +++ b/src/kamokan_impl/general_pastie_response.cpp @@ -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 #include @@ -45,7 +46,7 @@ namespace kamokan { boost::string_view token = get_search_token(cgi_env()); m_pastie_info = - storage().retrieve_pastie(token, settings().as("max_token_length")); + storage().retrieve_pastie(token, settings().as("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 diff --git a/src/kamokan_impl/general_pastie_response.hpp b/src/kamokan_impl/general_pastie_response.hpp index 2c1577a..0cdbbac 100644 --- a/src/kamokan_impl/general_pastie_response.hpp +++ b/src/kamokan_impl/general_pastie_response.hpp @@ -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; diff --git a/src/kamokan_impl/pastie_response.cpp b/src/kamokan_impl/pastie_response.cpp index 2a9fa2e..8adf705 100644 --- a/src/kamokan_impl/pastie_response.cpp +++ b/src/kamokan_impl/pastie_response.cpp @@ -20,7 +20,6 @@ #include "settings_bag.hpp" #include "escapist.hpp" #include "cgi_env.hpp" -#include "spdlog.hpp" #include "highlight_functions.hpp" #include #include @@ -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 diff --git a/src/kamokan_impl/pastie_response.hpp b/src/kamokan_impl/pastie_response.hpp index aa60ca4..267f8ba 100644 --- a/src/kamokan_impl/pastie_response.hpp +++ b/src/kamokan_impl/pastie_response.hpp @@ -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; diff --git a/src/kamokan_impl/retrieve_pastie.lua b/src/kamokan_impl/retrieve_pastie.lua index bcaee3e..7b68bb1 100644 --- a/src/kamokan_impl/retrieve_pastie.lua +++ b/src/kamokan_impl/retrieve_pastie.lua @@ -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} diff --git a/src/kamokan_impl/storage.cpp b/src/kamokan_impl/storage.cpp index c93c39d..c58939e 100644 --- a/src/kamokan_impl/storage.cpp +++ b/src/kamokan_impl/storage.cpp @@ -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(get_integer(pastie_reply[3])); + retval.comment = get_string(pastie_reply[5]); if (selfdes and not deleted) { auto statuslog = spdlog::get("statuslog"); diff --git a/src/kamokan_impl/storage.hpp b/src/kamokan_impl/storage.hpp index e04dc31..f4afe4f 100644 --- a/src/kamokan_impl/storage.hpp +++ b/src/kamokan_impl/storage.hpp @@ -47,6 +47,8 @@ namespace kamokan { boost::optional pastie; boost::optional lang; boost::optional error; + boost::optional 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; diff --git a/test/simulation/fake_storage.cpp b/test/simulation/fake_storage.cpp index 2553e15..cde7e89 100644 --- a/test/simulation/fake_storage.cpp +++ b/test/simulation/fake_storage.cpp @@ -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(), diff --git a/test/simulation/fake_storage.hpp b/test/simulation/fake_storage.hpp index c038dbe..dd7ea68 100644 --- a/test/simulation/fake_storage.hpp +++ b/test/simulation/fake_storage.hpp @@ -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& submitted_pasties() const;