1
0
Fork 0
mirror of https://github.com/KingDuckZ/kamokan.git synced 2024-11-23 00:33:44 +00:00

Use lua script to retrieve a pastie from its token.

The self-destruct logic is in lua now.
This commit is contained in:
King_DuckZ 2017-06-22 09:28:45 +01:00
parent 48ccb8eec5
commit b421299884
7 changed files with 128 additions and 14 deletions

@ -1 +1 @@
Subproject commit 0aee978661e0f31722a28ff039490a98c829644b
Subproject commit d2fff64381402a4ada9bbe3673603bbc81b2d0f6

View file

@ -22,6 +22,7 @@ add_library(${PROJECT_NAME} STATIC
string_conv.cpp
edit_response.cpp
general_pastie_response.cpp
${CMAKE_CURRENT_BINARY_DIR}/include/lua_scripts_for_redis.cpp
)
target_include_directories(${PROJECT_NAME}
@ -62,3 +63,10 @@ configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/kamokan_config.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/include/kamokan_config.h"
)
add_custom_command(
OUTPUT include/lua_scripts_for_redis.cpp
COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" -P ${CMAKE_CURRENT_SOURCE_DIR}/lua_to_cpp.cmake
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/retrieve_pastie.lua ${CMAKE_CURRENT_SOURCE_DIR}/save_pastie.lua
COMMENT "Embedding save/load lua scripts into the c++ code"
)

View file

@ -0,0 +1,27 @@
/* Copyright 2017, Michele Santullo
* This file is part of "kamokan".
*
* "kamokan" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "kamokan" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "kamokan". If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstddef>
namespace kamokan {
extern const char g_save_script[];
extern const char g_load_script[];
extern const std::size_t g_save_script_size;
extern const std::size_t g_load_script_size;
} //namespace kamokan

View file

@ -0,0 +1,31 @@
file(READ ${SOURCE_DIR}/retrieve_pastie.lua retrieve_pastie)
file(READ ${SOURCE_DIR}/save_pastie.lua save_pastie)
string(REGEX REPLACE "[ \t]*=[ \t]*" "=" retrieve_pastie "${retrieve_pastie}")
string(REGEX REPLACE "[ \t]*=[ \t]*" "=" save_pastie "${save_pastie}")
string(REGEX REPLACE ",[ \t]*" "," retrieve_pastie "${retrieve_pastie}")
string(REGEX REPLACE ",[ \t]*" "," save_pastie "${save_pastie}")
string(REGEX REPLACE "(^|\n)[ \t]+" "\\1" retrieve_pastie "${retrieve_pastie}")
string(REGEX REPLACE "(^|\n)[ \t]+" "\\1" save_pastie "${save_pastie}")
string(LENGTH "${retrieve_pastie}" retrieve_pastie_length)
string(LENGTH "${save_pastie}" save_pastie_length)
set(lua_scripts_for_redis_content "//File autogenerated by cmake, changes will be lost
#include <cstddef>
namespace kamokan {
extern const char g_save_script[] = R\"lua(${save_pastie})lua\";
extern const char g_load_script[] = R\"lua(${retrieve_pastie})lua\";
extern const std::size_t g_save_script_size = ${save_pastie_length} + 1;
extern const std::size_t g_load_script_size = ${retrieve_pastie_length} + 1;
} //namespace kamokan
")
file(WRITE
include/lua_scripts_for_redis.cpp
"${lua_scripts_for_redis_content}"
)
unset(lua_scripts_for_redis_content)
unset(save_pastie_length)
unset(retrieve_pastie_length)
unset(save_pastie)
unset(retrieve_pastie)

View file

@ -0,0 +1,10 @@
local token = KEYS[1]
local result = redis.call("HMGET", token, "pastie", "selfdes", "lang")
local selfdes = 0
local deleted = 0
if result[2] == 1 then
deleted = redis.call("DEL", token)
selfdes = 1
end
return {result[1], selfdes, deleted, result[3]}

View file

@ -0,0 +1,29 @@
function num_to_value (num)
local retval = ""
local running = true
while (running)
do
local remainder = num % 26
retval = string.char(97 + remainder) .. retval
num = math.floor(num / 26)
running = (num ~= 0)
end
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
)
return token

View file

@ -23,6 +23,7 @@
#include "spdlog.hpp"
#include "truncated_string.hpp"
#include "string_conv.hpp"
#include "lua_scripts_for_redis.hpp"
#include <cassert>
#include <ciso646>
#include <string>
@ -129,6 +130,7 @@ namespace kamokan {
const std::string& parRemoteIP
) const {
using tawashi::ErrorReasons;
using redis::RedisInt;
if (not is_connected())
return make_submission_result(ErrorReasons::RedisDisconnected);
@ -156,7 +158,7 @@ namespace kamokan {
"pastie", parText,
"max_ttl", dhandy::lexical_cast<std::string>(parExpiry),
"lang", parLang,
"selfdes", (parSelfDestruct ? "1" : "0"))
"selfdes", static_cast<RedisInt>(parSelfDestruct ? 1 : 0))
) {
redis.set(parRemoteIP, "");
redis.expire(parRemoteIP, m_settings->as<uint32_t>("resubmit_wait"));
@ -168,7 +170,6 @@ namespace kamokan {
}
auto Storage::retrieve_pastie (const boost::string_view& parToken, uint32_t parMaxTokenLen) const -> RetrievedPastie {
using opt_string = redis::IncRedis::opt_string;
using opt_string_list = redis::IncRedis::opt_string_list;
RetrievedPastie retval;
@ -176,18 +177,26 @@ namespace kamokan {
if (not retval.valid_token)
return retval;
opt_string_list pastie_reply = m_redis->hmget(parToken, "pastie", "selfdes", "lang");
retval.pastie = (pastie_reply and not pastie_reply->empty() ? (*pastie_reply)[0] : opt_string());
opt_string selfdes = (pastie_reply and pastie_reply->size() > 1 ? (*pastie_reply)[1] : opt_string());
retval.lang = (pastie_reply and pastie_reply->size() > 2 ? (*pastie_reply)[2] : opt_string());
if (selfdes and string_conv<bool>(*selfdes)) {
const bool deleted = m_redis->del(parToken);
retval.self_destructed = deleted;
if (not deleted) {
auto statuslog = spdlog::get("statuslog");
statuslog->error("Pastie \"{}\" was marked as self-destructing but DEL failed to delete it", parToken);
}
redis::Script retrieve = m_redis->command().make_script(boost::string_view(g_load_script, g_load_script_size - 1));
auto batch = m_redis->command().make_batch();
retrieve.run(batch, std::make_tuple(parToken), std::make_tuple());
auto raw_replies = batch.replies();
if (raw_replies.empty())
return retval;
assert(not raw_replies.front().is_error());
auto pastie_reply = get_array(raw_replies.front());
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.self_destructed = selfdes and deleted;
if (selfdes and not deleted) {
auto statuslog = spdlog::get("statuslog");
statuslog->error("Pastie \"{}\" was marked as self-destructing but DEL failed to delete it", parToken);
}
#if defined(SPDLOG_DEBUG_ON)