From 6222f1e1b1d5abdf36e949458d06d4659b7435e0 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Fri, 23 Jun 2017 21:49:28 +0100 Subject: [PATCH] Use the lua script to save new pasties. I had to add a {store:} prefix, see this: https://stackoverflow.com/questions/38720084/generate-new-key-inside-evalsha --- src/kamokan_impl/CMakeLists.txt | 1 - src/kamokan_impl/retrieve_pastie.lua | 6 +- src/kamokan_impl/save_pastie.lua | 42 ++++++++---- src/kamokan_impl/storage.cpp | 64 +++++++++++-------- src/kamokan_impl/string_conv.hpp | 6 ++ test/simulation/CMakeLists.txt | 1 + .../simulation}/num_to_token.cpp | 0 .../simulation}/num_to_token.hpp | 0 8 files changed, 78 insertions(+), 42 deletions(-) rename {src/kamokan_impl => test/simulation}/num_to_token.cpp (100%) rename {src/kamokan_impl => test/simulation}/num_to_token.hpp (100%) diff --git a/src/kamokan_impl/CMakeLists.txt b/src/kamokan_impl/CMakeLists.txt index 441052d..8045576 100644 --- a/src/kamokan_impl/CMakeLists.txt +++ b/src/kamokan_impl/CMakeLists.txt @@ -8,7 +8,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) add_library(${PROJECT_NAME} STATIC response.cpp submit_paste_response.cpp - num_to_token.cpp index_response.cpp pastie_response.cpp ini_file.cpp diff --git a/src/kamokan_impl/retrieve_pastie.lua b/src/kamokan_impl/retrieve_pastie.lua index 4d325fd..7ee677f 100644 --- a/src/kamokan_impl/retrieve_pastie.lua +++ b/src/kamokan_impl/retrieve_pastie.lua @@ -1,5 +1,7 @@ local token = KEYS[1] -local result = redis.call("HMGET", token, "pastie", "selfdes", "lang") +local token_prefix = ARGV[1] +local full_token = token_prefix .. token +local result = redis.call("HMGET", full_token, "pastie", "selfdes", "lang") if false == result[1] then return redis.error_reply("PastieNotFound") end @@ -7,7 +9,7 @@ end local selfdes = 0 local deleted = 0 if result[2] == 1 then - deleted = redis.call("DEL", token) + deleted = redis.call("DEL", full_token) selfdes = 1 end diff --git a/src/kamokan_impl/save_pastie.lua b/src/kamokan_impl/save_pastie.lua index 3dc39c9..f87ca3a 100644 --- a/src/kamokan_impl/save_pastie.lua +++ b/src/kamokan_impl/save_pastie.lua @@ -1,4 +1,4 @@ -function num_to_value (num) +local function num_to_token (num) local retval = "" local running = true @@ -12,18 +12,34 @@ function num_to_value (num) return retval end -paste_counter = KEYS[1] -next_id = redis.call("INCR", paste_counter) - 1 -token = num_to_token(next_id) -text = ARGV[1] -ttl = ARGV[2] -lang = ARGV[3] -selfdestruct = ARGV[4] -redis.call("HMSET", token, - "pastie", text, - "max_ttl", ttl, - "lang", lang, - "selfdes", selfdestruct +local paste_counter_token = KEYS[1] +local flooding_token = KEYS[2] + +local flooding_result = redis.call("GET", flooding_token) +if flooding_result then + return redis.error_reply("UserFlooding") +end + +local token_prefix = ARGV[1] +local text = ARGV[2] +local ttl = ARGV[3] +local lang = ARGV[4] +local selfdestruct = ARGV[5] +local flood_wait = ARGV[6] + +local next_id = redis.call("INCR", paste_counter_token) - 1 +local token = num_to_token(next_id) +local saved = redis.call("HMSET", token_prefix .. token, + "pastie", text, + "max_ttl", ttl, + "lang", lang, + "selfdes", selfdestruct ) +if saved then + redis.call("SET", flooding_token, "") + redis.call("EXPIRE", flooding_token, flood_wait) +else + return redis.error_reply("PastieNotSaved") +end return token diff --git a/src/kamokan_impl/storage.cpp b/src/kamokan_impl/storage.cpp index aed733b..a9085bc 100644 --- a/src/kamokan_impl/storage.cpp +++ b/src/kamokan_impl/storage.cpp @@ -18,12 +18,12 @@ #include "storage.hpp" #include "settings_bag.hpp" #include "incredis/incredis.hpp" -#include "num_to_token.hpp" #include "duckhandy/stringize.h" #include "spdlog.hpp" #include "truncated_string.hpp" #include "string_conv.hpp" #include "lua_scripts_for_redis.hpp" +#include "redis_to_error_reason.hpp" #include #include #include @@ -32,6 +32,8 @@ namespace kamokan { namespace { + const char g_token_prefix[] = "kamokan:{store:}"; + redis::IncRedis make_incredis (const SettingsBag& parSettings) { using redis::IncRedis; @@ -130,54 +132,64 @@ namespace kamokan { const std::string& parRemoteIP ) const { using tawashi::ErrorReasons; - using redis::RedisInt; + using boost::string_view; + using dhandy::lexical_cast; if (not is_connected()) return make_submission_result(ErrorReasons::RedisDisconnected); assert(m_redis); auto& redis = *m_redis; - if (redis.get(parRemoteIP)) { - //please wait and submit again - return make_submission_result(ErrorReasons::UserFlooding); + + redis::Script retrieve = m_redis->command().make_script(string_view(g_save_script, g_save_script_size)); + auto batch = m_redis->command().make_batch(); + { + string_view paste_counter_token("{store:}paste_counter"); + std::string prefix(g_token_prefix); + const auto expiry = lexical_cast(parExpiry); + const auto self_des = string_view(parSelfDestruct ? "1" : "0"); + const auto flood_wait = m_settings->as("resubmit_wait"); + retrieve.run(batch, + std::make_tuple(paste_counter_token, prefix + parRemoteIP), + std::make_tuple(prefix, parText, expiry, parLang, self_des, flood_wait) + ); + } + auto raw_replies = batch.replies(); + auto statuslog = spdlog::get("statuslog"); + if (raw_replies.empty()) { + statuslog->error("Received empty reply from redis"); + return make_submission_result(ErrorReasons::UnknownReason); } - auto statuslog = spdlog::get("statuslog"); + if (raw_replies.front().is_error()) { + statuslog->error("Received error reply from redis"); + return make_submission_result(redis_to_error_reason(get_error_string(raw_replies.front()))); + } + + std::string token = get_string(raw_replies.front()); + if (statuslog->should_log(spdlog::level::info)) { statuslog->info( - "Submitting pastie of size {} to redis -> \"{}\"", + "Saved pastie of size {} to redis token \"{}\" -> \"{}\"", parText.size(), + token, tawashi::truncated_string(parText, 30) ); } - - const auto next_id = redis.incr("paste_counter"); - std::string token = num_to_token(next_id); - assert(not token.empty()); - if (redis.hmset(token, - "pastie", parText, - "max_ttl", dhandy::lexical_cast(parExpiry), - "lang", parLang, - "selfdes", static_cast(parSelfDestruct ? 1 : 0)) - ) { - redis.set(parRemoteIP, ""); - redis.expire(parRemoteIP, m_settings->as("resubmit_wait")); - if (redis.expire(token, parExpiry)) - return make_submission_result(std::move(token)); - } - - return make_submission_result(ErrorReasons::PastieNotSaved); + return make_submission_result(std::move(token)); } auto Storage::retrieve_pastie (const boost::string_view& parToken, uint32_t parMaxTokenLen) const -> RetrievedPastie { + using boost::string_view; + RetrievedPastie retval; retval.valid_token = is_valid_token(parToken, parMaxTokenLen); if (not retval.valid_token) return retval; - redis::Script retrieve = m_redis->command().make_script(boost::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(); - retrieve.run(batch, std::make_tuple(parToken), std::make_tuple()); + retrieve.run(batch, std::make_tuple(parToken), std::make_tuple(string_view(g_token_prefix))); auto raw_replies = batch.replies(); if (raw_replies.empty()) return retval; diff --git a/src/kamokan_impl/string_conv.hpp b/src/kamokan_impl/string_conv.hpp index 04bc4e5..b72609b 100644 --- a/src/kamokan_impl/string_conv.hpp +++ b/src/kamokan_impl/string_conv.hpp @@ -50,6 +50,12 @@ namespace kamokan { return dhandy::lexical_cast(parStr); } + template <> + [[gnu::pure,gnu::always_inline]] inline + long long string_conv (boost::string_view parStr) { + return dhandy::lexical_cast(parStr); + } + template <> inline std::string string_conv (boost::string_view parStr) { diff --git a/test/simulation/CMakeLists.txt b/test/simulation/CMakeLists.txt index 881722f..5401c94 100644 --- a/test/simulation/CMakeLists.txt +++ b/test/simulation/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(${PROJECT_NAME} test_index_response.cpp test_submit_pastie.cpp fake_storage.cpp + num_to_token.cpp ) target_include_directories(${PROJECT_NAME} diff --git a/src/kamokan_impl/num_to_token.cpp b/test/simulation/num_to_token.cpp similarity index 100% rename from src/kamokan_impl/num_to_token.cpp rename to test/simulation/num_to_token.cpp diff --git a/src/kamokan_impl/num_to_token.hpp b/test/simulation/num_to_token.hpp similarity index 100% rename from src/kamokan_impl/num_to_token.hpp rename to test/simulation/num_to_token.hpp