mirror of
https://github.com/KingDuckZ/kamokan.git
synced 2024-12-27 21:35:41 +00:00
Refactoring.
IncRedis is now held by Response, if requested by the base class. Response objects know their names, and they use it to load the html (soon to be mustache) data from disk. Main only prepares a factory, the factory then instantiates the actual Response. The code now correctly serves index.cgi when the request is /. Remove kakoune's safe_ptr from inside src and put an updated one in lib/kakoune.
This commit is contained in:
parent
4bf8dfc29f
commit
680f13e1f6
19 changed files with 400 additions and 195 deletions
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
|
|||
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||
project(tawashi_top)
|
||||
|
||||
set(TAWSHI_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(TAWASHI_SOURCE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
add_subdirectory(lib/incredis)
|
||||
add_subdirectory(src)
|
||||
|
|
|
@ -3,7 +3,8 @@ processes = 4
|
|||
master = 1
|
||||
socket = /run/uwsgi/%n.sock
|
||||
cgi = /srv/http/tawashi/%n.cgi
|
||||
chmod-socket = 666
|
||||
chmod-socket = 664
|
||||
strict = true
|
||||
gid = http
|
||||
plugins = cgi
|
||||
chdir = /srv/http/tawashi
|
||||
|
|
|
@ -3,19 +3,23 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
#if !defined(NDEBUG) && !defined(KAK_DEBUG)
|
||||
# define KAK_DEBUG
|
||||
#endif
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
struct WorstMatch { [[gnu::always_inline]] WorstMatch(...) {} };
|
||||
struct RefCountable
|
||||
{
|
||||
int refcount = 0;
|
||||
virtual ~RefCountable() = default;
|
||||
};
|
||||
|
||||
[[gnu::always_inline]]
|
||||
inline void ref_ptr_moved(WorstMatch, void*, void*) noexcept {}
|
||||
struct RefCountablePolicy
|
||||
{
|
||||
static void inc_ref(RefCountable* r, void*) noexcept { ++r->refcount; }
|
||||
static void dec_ref(RefCountable* r, void*) { if (--r->refcount == 0) delete r; }
|
||||
static void ptr_moved(RefCountable*, void*, void*) noexcept {}
|
||||
};
|
||||
|
||||
template<typename T, typename TForOverload = T>
|
||||
template<typename T, typename Policy = RefCountablePolicy>
|
||||
struct RefPtr
|
||||
{
|
||||
RefPtr() = default;
|
||||
|
@ -87,47 +91,25 @@ private:
|
|||
void acquire()
|
||||
{
|
||||
if (m_ptr)
|
||||
inc_ref_count(static_cast<TForOverload*>(m_ptr), this);
|
||||
Policy::inc_ref(m_ptr, this);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
void release()
|
||||
{
|
||||
if (m_ptr)
|
||||
dec_ref_count(static_cast<TForOverload*>(m_ptr), this);
|
||||
m_ptr = nullptr;
|
||||
Policy::dec_ref(m_ptr, this);
|
||||
}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
void moved(void* from)
|
||||
noexcept(noexcept(ref_ptr_moved(static_cast<TForOverload*>(nullptr), nullptr, nullptr)))
|
||||
noexcept(noexcept(Policy::ptr_moved(nullptr, nullptr, nullptr)))
|
||||
{
|
||||
if (m_ptr)
|
||||
ref_ptr_moved(static_cast<TForOverload*>(m_ptr), from, this);
|
||||
}
|
||||
};
|
||||
|
||||
struct RefCountable
|
||||
{
|
||||
int refcount = 0;
|
||||
virtual ~RefCountable() = default;
|
||||
|
||||
friend void inc_ref_count(RefCountable* r, void*)
|
||||
{
|
||||
++r->refcount;
|
||||
}
|
||||
|
||||
friend void dec_ref_count(RefCountable* r, void*)
|
||||
{
|
||||
if (--r->refcount == 0)
|
||||
delete r;
|
||||
Policy::ptr_moved(m_ptr, from, this);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#if defined(KAK_DEBUG)
|
||||
# undef KAK_DEBUG
|
||||
#endif
|
||||
|
||||
#endif // ref_ptr_hh_INCLUDED
|
|
@ -3,24 +3,22 @@
|
|||
|
||||
// #define SAFE_PTR_TRACK_CALLSTACKS
|
||||
|
||||
//King_DuckZ:
|
||||
#include <cassert>
|
||||
#define kak_assert(a) assert(a)
|
||||
|
||||
//#include "assert.hh"
|
||||
#include "ref_ptr.hh"
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#ifdef SAFE_PTR_TRACK_CALLSTACKS
|
||||
#include "backtrace.hh"
|
||||
#include "vector.hh"
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#define kak_assert assert
|
||||
|
||||
#if !defined(NDEBUG) && !defined(KAK_DEBUG)
|
||||
# define KAK_DEBUG
|
||||
#endif
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
|
@ -31,6 +29,7 @@ class SafeCountable
|
|||
public:
|
||||
#ifdef KAK_DEBUG
|
||||
SafeCountable() : m_count(0) {}
|
||||
SafeCountable (SafeCountable&&) : m_count(0) {}
|
||||
~SafeCountable()
|
||||
{
|
||||
kak_assert(m_count == 0);
|
||||
|
@ -39,37 +38,8 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
friend void inc_ref_count(const SafeCountable* sc, void* /*ptr*/)
|
||||
{
|
||||
++sc->m_count;
|
||||
#ifdef SAFE_PTR_TRACK_CALLSTACKS
|
||||
sc->m_callstacks.emplace_back(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
friend void dec_ref_count(const SafeCountable* sc, void* /*ptr*/)
|
||||
{
|
||||
--sc->m_count;
|
||||
kak_assert(sc->m_count >= 0);
|
||||
#ifdef SAFE_PTR_TRACK_CALLSTACKS
|
||||
auto it = std::find_if(sc->m_callstacks.begin(), sc->m_callstacks.end(),
|
||||
[=](const Callstack& cs) { return cs.ptr == ptr; });
|
||||
kak_assert(it != sc->m_callstacks.end());
|
||||
sc->m_callstacks.erase(it);
|
||||
#endif
|
||||
}
|
||||
|
||||
friend void ref_ptr_moved(const SafeCountable* /*sc*/, void* /*from*/, void* /*to*/)
|
||||
{
|
||||
#ifdef SAFE_PTR_TRACK_CALLSTACKS
|
||||
auto it = std::find_if(sc->m_callstacks.begin(), sc->m_callstacks.end(),
|
||||
[=](const Callstack& cs) { return cs.ptr == from; });
|
||||
kak_assert(it != sc->m_callstacks.end());
|
||||
it->ptr = to;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct SafeCountablePolicy;
|
||||
#ifdef SAFE_PTR_TRACK_CALLSTACKS
|
||||
struct Callstack
|
||||
{
|
||||
|
@ -81,26 +51,59 @@ private:
|
|||
mutable Vector<Callstack> m_callstacks;
|
||||
#endif
|
||||
mutable int m_count;
|
||||
#else
|
||||
[[gnu::always_inline]]
|
||||
friend void inc_ref_count(const SafeCountable* /*sc*/, void* /*ptr*/) {}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
friend void dec_ref_count(const SafeCountable* /*sc*/, void* /*ptr*/) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
using PropagateConst = typename std::conditional<std::is_const<T>::value, const U, U>::type;
|
||||
struct SafeCountablePolicy
|
||||
{
|
||||
#ifdef KAK_DEBUG
|
||||
static void inc_ref(const SafeCountable* sc, void* ptr) noexcept
|
||||
{
|
||||
++sc->m_count;
|
||||
#ifdef SAFE_PTR_TRACK_CALLSTACKS
|
||||
sc->m_callstacks.emplace_back(ptr);
|
||||
#else
|
||||
static_cast<void>(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dec_ref(const SafeCountable* sc, void* ptr) noexcept
|
||||
{
|
||||
--sc->m_count;
|
||||
kak_assert(sc->m_count >= 0);
|
||||
#ifdef SAFE_PTR_TRACK_CALLSTACKS
|
||||
auto it = std::find_if(sc->m_callstacks.begin(), sc->m_callstacks.end(),
|
||||
[=](const SafeCountable::Callstack& cs) { return cs.ptr == ptr; });
|
||||
kak_assert(it != sc->m_callstacks.end());
|
||||
sc->m_callstacks.erase(it);
|
||||
#else
|
||||
static_cast<void>(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ptr_moved(const SafeCountable* sc, void* from, void* to) noexcept
|
||||
{
|
||||
#ifdef SAFE_PTR_TRACK_CALLSTACKS
|
||||
auto it = std::find_if(sc->m_callstacks.begin(), sc->m_callstacks.end(),
|
||||
[=](const SafeCountable::Callstack& cs) { return cs.ptr == from; });
|
||||
kak_assert(it != sc->m_callstacks.end());
|
||||
it->ptr = to;
|
||||
#else
|
||||
static_cast<void>(sc);
|
||||
static_cast<void>(from);
|
||||
static_cast<void>(to);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static void inc_ref(const SafeCountable*, void*) noexcept {}
|
||||
static void dec_ref(const SafeCountable*, void*) noexcept {}
|
||||
static void ptr_moved(const SafeCountable*, void*, void*) noexcept {}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using SafePtr = RefPtr<T, PropagateConst<T, SafeCountable>>;
|
||||
using SafePtr = RefPtr<T, SafeCountablePolicy>;
|
||||
|
||||
}
|
||||
|
||||
#if defined(KAK_DEBUG)
|
||||
# undef KAK_DEBUG
|
||||
#endif
|
||||
#undef kak_assert
|
||||
|
||||
#endif // safe_ptr_hh_INCLUDED
|
|
@ -25,6 +25,7 @@ add_executable(${PROJECT_NAME}
|
|||
pastie_response.cpp
|
||||
ini_file.cpp
|
||||
pathname/pathname.cpp
|
||||
response_factory.cpp
|
||||
)
|
||||
|
||||
configure_file(
|
||||
|
@ -34,10 +35,11 @@ configure_file(
|
|||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include
|
||||
PRIVATE ${TAWASHI_SOURCE_ROOT}/lib/kakoune
|
||||
)
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM
|
||||
PRIVATE ${Boost_INCLUDE_DIRS}
|
||||
PRIVATE ${TAWASHI_SOURCE_ROOT}/lib/bette-enums
|
||||
PRIVATE ${TAWASHI_SOURCE_ROOT}/lib/better-enums
|
||||
PRIVATE ${CURL_INCLUDE_DIR}
|
||||
PRIVATE ${SourceHighlight_INCLUDE_DIR}
|
||||
)
|
||||
|
|
|
@ -19,20 +19,13 @@
|
|||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
IndexResponse::IndexResponse (const boost::string_ref& parBaseURI) :
|
||||
Response(Response::ContentType, "text/html", parBaseURI)
|
||||
IndexResponse::IndexResponse (const IniFile& parIni) :
|
||||
Response(Response::ContentType, "text/html", "index", parIni, false)
|
||||
{
|
||||
}
|
||||
|
||||
void IndexResponse::on_send (std::ostream& parStream) {
|
||||
std::string html(R"(
|
||||
<form action="http://127.0.0.1:8080/paste.cgi" method="POST" accept-charset="UTF-8">
|
||||
<textarea name="pastie" cols="80" rows="24"></textarea>
|
||||
<br>
|
||||
<button type="submit">tawashi</button>
|
||||
</br>
|
||||
</form>
|
||||
)");
|
||||
std::string html(load_mustache());
|
||||
|
||||
boost::replace_all(html, "{base_uri}", base_uri());
|
||||
parStream << html;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
namespace tawashi {
|
||||
class IndexResponse : public Response {
|
||||
public:
|
||||
explicit IndexResponse (const boost::string_ref& parBaseURI);
|
||||
explicit IndexResponse (const IniFile& parIni);
|
||||
|
||||
private:
|
||||
virtual void on_send (std::ostream& parStream) override;
|
||||
|
|
|
@ -17,13 +17,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <iterator>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace tawashi {
|
||||
class IniFile {
|
||||
class IniFile : public Kakoune::SafeCountable {
|
||||
public:
|
||||
typedef boost::container::flat_map<boost::string_ref, boost::string_ref> KeyValueMapType;
|
||||
typedef boost::container::flat_map<boost::string_ref, KeyValueMapType> IniMapType;
|
||||
|
|
54
src/main.cpp
54
src/main.cpp
|
@ -15,13 +15,14 @@
|
|||
* along with "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "incredis/incredis.hpp"
|
||||
#include "tawashiConfig.h"
|
||||
#include "submit_paste_response.hpp"
|
||||
#include "pastie_response.hpp"
|
||||
#include "index_response.hpp"
|
||||
#include "response_factory.hpp"
|
||||
#include "cgi_env.hpp"
|
||||
#include "ini_file.hpp"
|
||||
#include "safe_stack_object.hpp"
|
||||
#include "pathname/pathname.hpp"
|
||||
#include "duckhandy/compatibility.h"
|
||||
#include "duckhandy/lexical_cast.hpp"
|
||||
|
@ -50,51 +51,36 @@ namespace {
|
|||
return full_path.path();
|
||||
}
|
||||
|
||||
redis::IncRedis make_incredis (const tawashi::IniFile::KeyValueMapType& parSettings) {
|
||||
using redis::IncRedis;
|
||||
|
||||
if (parSettings.at("redis_mode") == "inet") {
|
||||
return IncRedis(
|
||||
std::string(parSettings.at("redis_server")),
|
||||
dhandy::lexical_cast<uint16_t>(parSettings.at("redis_port"))
|
||||
);
|
||||
}
|
||||
else if (parSettings.at("redis_mode") == "sock") {
|
||||
return IncRedis(std::string(parSettings.at("redis_sock")));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Unknown setting for \"redis_mode\", valid settings are \"inet\" or \"sock\"");
|
||||
}
|
||||
template <typename T>
|
||||
std::unique_ptr<tawashi::Response> make_response (const tawashi::IniFile& parIni) {
|
||||
return static_cast<std::unique_ptr<tawashi::Response>>(std::make_unique<T>(parIni));
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
int main() {
|
||||
using curry::SafeStackObject;
|
||||
using tawashi::IndexResponse;
|
||||
using tawashi::SubmitPasteResponse;
|
||||
using tawashi::PastieResponse;
|
||||
using tawashi::Response;
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
std::cerr << "Loading config: \"" << config_file_path() << "\"\n";
|
||||
#endif
|
||||
std::ifstream conf(config_file_path());
|
||||
conf >> std::noskipws;
|
||||
tawashi::IniFile ini = tawashi::IniFile(std::istream_iterator<char>(conf), std::istream_iterator<char>());
|
||||
auto ini = SafeStackObject<tawashi::IniFile>(std::istream_iterator<char>(conf), std::istream_iterator<char>());
|
||||
conf.close();
|
||||
const auto& settings = ini.parsed().at("tawashi");
|
||||
|
||||
auto incredis = make_incredis(settings);
|
||||
incredis.connect();
|
||||
|
||||
tawashi::cgi::Env cgi_env;
|
||||
const boost::string_ref& base_uri = settings.at("base_uri");
|
||||
if (cgi_env.path_info() == "/index.cgi") {
|
||||
tawashi::IndexResponse resp(base_uri);
|
||||
resp.send();
|
||||
}
|
||||
else if (cgi_env.path_info() == "/paste.cgi") {
|
||||
tawashi::SubmitPasteResponse resp(incredis, base_uri);
|
||||
resp.send();
|
||||
}
|
||||
else {
|
||||
tawashi::PastieResponse resp(incredis, base_uri);
|
||||
resp.send();
|
||||
}
|
||||
tawashi::ResponseFactory resp_factory(ini);
|
||||
resp_factory.register_maker("index.cgi", &make_response<IndexResponse>);
|
||||
resp_factory.register_maker("", &make_response<IndexResponse>);
|
||||
resp_factory.register_maker("paste.cgi", &make_response<SubmitPasteResponse>);
|
||||
resp_factory.register_jolly_maker(&make_response<PastieResponse>);
|
||||
|
||||
std::unique_ptr<Response> response = resp_factory.make_response(cgi_env.path_info().substr(1));
|
||||
response->send();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,9 +23,8 @@
|
|||
#include <sstream>
|
||||
|
||||
namespace tawashi {
|
||||
PastieResponse::PastieResponse (redis::IncRedis& parRedis, const boost::string_ref& parBaseURI) :
|
||||
Response(Response::ContentType, "text/html", parBaseURI),
|
||||
m_redis(parRedis),
|
||||
PastieResponse::PastieResponse (const IniFile& parIni) :
|
||||
Response(Response::ContentType, "text/html", "", parIni, true),
|
||||
m_plain_text(false)
|
||||
{
|
||||
}
|
||||
|
@ -54,7 +53,8 @@ namespace tawashi {
|
|||
}
|
||||
|
||||
auto token = boost::string_ref(cgi_env().path_info()).substr(1);
|
||||
opt_string pastie = m_redis.get(token);
|
||||
auto& redis = this->redis();
|
||||
opt_string pastie = redis.get(token);
|
||||
if (not pastie) {
|
||||
}
|
||||
|
||||
|
|
|
@ -21,20 +21,15 @@
|
|||
#include <string>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
namespace redis {
|
||||
class IncRedis;
|
||||
} //namespace redis
|
||||
|
||||
namespace tawashi {
|
||||
class PastieResponse : public Response {
|
||||
public:
|
||||
PastieResponse (redis::IncRedis& parRedis, const boost::string_ref& parBaseURI);
|
||||
explicit PastieResponse (const IniFile& parIni);
|
||||
|
||||
private:
|
||||
virtual void on_process() override;
|
||||
virtual void on_send (std::ostream& parStream) override;
|
||||
|
||||
redis::IncRedis& m_redis;
|
||||
std::string m_lang_file;
|
||||
bool m_plain_text;
|
||||
};
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
#ifndef assert_hh_INCLUDED
|
||||
#define assert_hh_INCLUDED
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
||||
class StringView;
|
||||
|
||||
// return true if user asked to ignore the error
|
||||
bool notify_fatal_error(StringView message);
|
||||
|
||||
void on_assert_failed(const char* message);
|
||||
|
||||
}
|
||||
|
||||
#define STRINGIFY(X) #X
|
||||
#define TOSTRING(X) STRINGIFY(X)
|
||||
|
||||
#ifdef KAK_DEBUG
|
||||
#define kak_assert(...) do { \
|
||||
if (not (__VA_ARGS__)) \
|
||||
on_assert_failed("assert failed \"" #__VA_ARGS__ \
|
||||
"\" at " __FILE__ ":" TOSTRING(__LINE__)); \
|
||||
} while (false)
|
||||
#else
|
||||
#define kak_assert(...) do {} while(false)
|
||||
#endif
|
||||
|
||||
|
||||
#endif // assert_hh_INCLUDED
|
|
@ -16,16 +16,57 @@
|
|||
*/
|
||||
|
||||
#include "response.hpp"
|
||||
#include "incredis/incredis.hpp"
|
||||
#include "ini_file.hpp"
|
||||
#include <utility>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace tawashi {
|
||||
Response::Response (Types parRespType, std::string&& parValue, const boost::string_ref& parBaseURI) :
|
||||
namespace {
|
||||
//boost::string_ref fetch_page_basename (const cgi::Env& parEnv) {
|
||||
// const boost::string_ref& path = parEnv.path_info();
|
||||
|
||||
// const std::size_t last_slash = path.rfind('/');
|
||||
// const std::size_t last_dot = path.rfind('.');
|
||||
// const std::size_t start_index = (path.npos == last_slash ? 0 : last_slash + 1);
|
||||
// const std::size_t substr_len = (path.size() - start_index - (last_dot == path.npos ? 0 : path.size() - last_dot));
|
||||
// assert(start_index <= path.size());
|
||||
// assert(substr_len < path.size() and substr_len - path.size() - start_index);
|
||||
// return path.substr(start_index, substr_len);
|
||||
//}
|
||||
|
||||
redis::IncRedis make_incredis (const tawashi::IniFile::KeyValueMapType& parSettings) {
|
||||
using redis::IncRedis;
|
||||
|
||||
if (parSettings.at("redis_mode") == "inet") {
|
||||
return IncRedis(
|
||||
std::string(parSettings.at("redis_server")),
|
||||
dhandy::lexical_cast<uint16_t>(parSettings.at("redis_port"))
|
||||
);
|
||||
}
|
||||
else if (parSettings.at("redis_mode") == "sock") {
|
||||
return IncRedis(std::string(parSettings.at("redis_sock")));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Unknown setting for \"redis_mode\", valid settings are \"inet\" or \"sock\"");
|
||||
}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
Response::Response (Types parRespType, std::string&& parValue, std::string&& parPageBaseName, const IniFile& parIni, bool parWantRedis) :
|
||||
m_resp_value(std::move(parValue)),
|
||||
m_base_uri(parBaseURI),
|
||||
m_base_uri(parIni.parsed().at("tawashi").at("base_uri")),
|
||||
//m_page_basename(fetch_page_basename(m_cgi_env)),
|
||||
m_page_basename(std::move(parPageBaseName)),
|
||||
m_resp_type(parRespType),
|
||||
m_header_sent(false)
|
||||
{
|
||||
if (parWantRedis) {
|
||||
m_redis = std::make_unique<redis::IncRedis>(make_incredis(parIni.parsed().at("tawashi")));
|
||||
m_redis->connect();
|
||||
}
|
||||
}
|
||||
|
||||
Response::~Response() noexcept = default;
|
||||
|
@ -34,6 +75,9 @@ namespace tawashi {
|
|||
}
|
||||
|
||||
void Response::send() {
|
||||
if (m_redis)
|
||||
m_redis->wait_for_connect();
|
||||
|
||||
this->on_process();
|
||||
|
||||
m_header_sent = true;
|
||||
|
@ -65,4 +109,27 @@ namespace tawashi {
|
|||
const boost::string_ref& Response::base_uri() const {
|
||||
return m_base_uri;
|
||||
}
|
||||
|
||||
const std::string& Response::page_basename() const {
|
||||
return m_page_basename;
|
||||
}
|
||||
|
||||
std::string Response::load_mustache() const {
|
||||
std::ostringstream oss;
|
||||
oss << "html/" << page_basename() << ".html.mstch";
|
||||
std::cerr << "Trying to load \"" << oss.str() << "\"\n";
|
||||
std::ifstream if_mstch(oss.str(), std::ios::binary | std::ios::in);
|
||||
|
||||
if (!if_mstch)
|
||||
throw std::runtime_error(std::string("File \"") + oss.str() + "\" not found");
|
||||
|
||||
std::ostringstream buffer;
|
||||
buffer << if_mstch.rdbuf();
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
redis::IncRedis& Response::redis() const {
|
||||
assert(m_redis);
|
||||
return *m_redis;
|
||||
}
|
||||
} //namespace tawashi
|
||||
|
|
|
@ -21,8 +21,15 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace redis {
|
||||
class IncRedis;
|
||||
} //namespace redis
|
||||
|
||||
namespace tawashi {
|
||||
class IniFile;
|
||||
|
||||
class Response {
|
||||
public:
|
||||
virtual ~Response() noexcept;
|
||||
|
@ -35,10 +42,13 @@ namespace tawashi {
|
|||
Location
|
||||
};
|
||||
|
||||
Response (Types parRespType, std::string&& parValue, const boost::string_ref& parBaseURI);
|
||||
Response (Types parRespType, std::string&& parValue, std::string&& parPageBaseName, const IniFile& parIni, bool parWantRedis);
|
||||
const cgi::Env& cgi_env() const;
|
||||
void change_type (Types parRespType, std::string&& parValue);
|
||||
const boost::string_ref& base_uri() const;
|
||||
const std::string& page_basename() const;
|
||||
std::string load_mustache() const;
|
||||
redis::IncRedis& redis() const;
|
||||
|
||||
private:
|
||||
virtual void on_process();
|
||||
|
@ -47,7 +57,9 @@ namespace tawashi {
|
|||
cgi::Env m_cgi_env;
|
||||
std::string m_resp_value;
|
||||
boost::string_ref m_base_uri;
|
||||
std::string m_page_basename;
|
||||
Types m_resp_type;
|
||||
std::unique_ptr<redis::IncRedis> m_redis;
|
||||
bool m_header_sent;
|
||||
};
|
||||
} //namespace tawashi
|
||||
|
|
63
src/response_factory.cpp
Normal file
63
src/response_factory.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "response_factory.hpp"
|
||||
#include "ini_file.hpp"
|
||||
#include <functional>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
|
||||
namespace tawashi {
|
||||
namespace {
|
||||
} //unnamed namespace
|
||||
|
||||
struct ResponseFactory::LocalData {
|
||||
Kakoune::SafePtr<IniFile> settings;
|
||||
boost::container::flat_map<std::string, ResponseMakerFunc> makers;
|
||||
ResponseMakerFunc jolly_maker;
|
||||
};
|
||||
|
||||
ResponseFactory::ResponseFactory (const Kakoune::SafePtr<IniFile>& parSettings) :
|
||||
m_local_data(std::make_unique<LocalData>())
|
||||
{
|
||||
m_local_data->settings = parSettings;
|
||||
|
||||
}
|
||||
|
||||
ResponseFactory::~ResponseFactory() noexcept = default;
|
||||
|
||||
std::unique_ptr<Response> ResponseFactory::make_response (const boost::string_ref& parName) {
|
||||
auto maker_it = m_local_data->makers.find(std::string(parName.data(), parName.size()));
|
||||
if (m_local_data->makers.end() != maker_it) {
|
||||
return maker_it->second(*m_local_data->settings);
|
||||
}
|
||||
else if (m_local_data->jolly_maker) {
|
||||
return m_local_data->jolly_maker(*m_local_data->settings);
|
||||
}
|
||||
else {
|
||||
assert(false);
|
||||
return std::unique_ptr<Response>();
|
||||
}
|
||||
}
|
||||
|
||||
void ResponseFactory::register_maker (std::string&& parName, ResponseMakerFunc parMaker) {
|
||||
m_local_data->makers[std::move(parName)] = parMaker;
|
||||
}
|
||||
|
||||
void ResponseFactory::register_jolly_maker (ResponseMakerFunc parMaker) {
|
||||
m_local_data->jolly_maker = parMaker;
|
||||
}
|
||||
} //namespace tawashi
|
43
src/response_factory.hpp
Normal file
43
src/response_factory.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* Copyright 2017, Michele Santullo
|
||||
* This file is part of "tawashi".
|
||||
*
|
||||
* "tawashi" 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.
|
||||
*
|
||||
* "tawashi" 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 "tawashi". If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "response.hpp"
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include <memory>
|
||||
|
||||
namespace tawashi {
|
||||
class IniFile;
|
||||
|
||||
class ResponseFactory {
|
||||
public:
|
||||
typedef std::function<std::unique_ptr<Response>(const IniFile&)> ResponseMakerFunc;
|
||||
|
||||
explicit ResponseFactory (const Kakoune::SafePtr<IniFile>& parSettings);
|
||||
~ResponseFactory() noexcept;
|
||||
|
||||
std::unique_ptr<Response> make_response(const boost::string_ref& parName);
|
||||
void register_maker (std::string&& parName, ResponseMakerFunc parMaker);
|
||||
void register_jolly_maker (ResponseMakerFunc parMaker);
|
||||
|
||||
private:
|
||||
struct LocalData;
|
||||
|
||||
std::unique_ptr<LocalData> m_local_data;
|
||||
};
|
||||
} //namespace tawashi
|
96
src/safe_stack_object.hpp
Normal file
96
src/safe_stack_object.hpp
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Copyright 2016, 2017 Michele "King_DuckZ" Santullo
|
||||
|
||||
This file is part of MyCurry.
|
||||
|
||||
MyCurry 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.
|
||||
|
||||
MyCurry 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 MyCurry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kakoune/safe_ptr.hh"
|
||||
#include <utility>
|
||||
|
||||
namespace curry {
|
||||
template <typename T>
|
||||
class SafeStackObject {
|
||||
public:
|
||||
typedef Kakoune::SafePtr<T> safe_ptr;
|
||||
|
||||
SafeStackObject();
|
||||
SafeStackObject (SafeStackObject&& parOther);
|
||||
SafeStackObject (const SafeStackObject& parOther) = delete;
|
||||
template <typename... Args> explicit SafeStackObject (Args&&... parArgs);
|
||||
~SafeStackObject() noexcept = default;
|
||||
|
||||
SafeStackObject& operator= (SafeStackObject&& parOther) = delete;
|
||||
SafeStackObject& operator= (const SafeStackObject& parOther) = delete;
|
||||
|
||||
operator Kakoune::SafePtr<T>&();
|
||||
safe_ptr& operator*();
|
||||
safe_ptr& operator->();
|
||||
|
||||
private:
|
||||
T m_obj;
|
||||
safe_ptr m_obj_ptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
SafeStackObject<T>::SafeStackObject() :
|
||||
m_obj(),
|
||||
m_obj_ptr(&m_obj)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeStackObject<T>::SafeStackObject (SafeStackObject&& parOther) :
|
||||
m_obj(std::move(parOther.m_obj)),
|
||||
m_obj_ptr(&m_obj)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename... Args>
|
||||
SafeStackObject<T>::SafeStackObject (Args&&... parArgs) :
|
||||
m_obj(std::forward<Args>(parArgs)...),
|
||||
m_obj_ptr(&m_obj)
|
||||
{
|
||||
}
|
||||
|
||||
//template <typename T>
|
||||
//SafeStackObject& SafeStackObject<T>::operator= (SafeStackObject&& parOther) {
|
||||
// m_obj = std::move(parOther.m_obj);
|
||||
// m_obj_ptr = std::move(parOther.m_obj_ptr);
|
||||
// m_ob
|
||||
//}
|
||||
|
||||
//template <typename T>
|
||||
//SafeStackObject& SafeStackObject<T>::operator= (const SafeStackObject& parOther) {
|
||||
//}
|
||||
|
||||
template <typename T>
|
||||
SafeStackObject<T>::operator Kakoune::SafePtr<T>&() {
|
||||
return m_obj_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto SafeStackObject<T>::operator*() -> safe_ptr& {
|
||||
return m_obj_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto SafeStackObject<T>::operator->() -> safe_ptr& {
|
||||
return m_obj_ptr;
|
||||
}
|
||||
} //namespace curry
|
|
@ -27,9 +27,8 @@ namespace tawashi {
|
|||
const char g_post_key[] = "pastie";
|
||||
} //unnamed namespace
|
||||
|
||||
SubmitPasteResponse::SubmitPasteResponse (redis::IncRedis& parRedis, const boost::string_ref& parBaseURI) :
|
||||
Response(Response::ContentType, "text/plain", parBaseURI),
|
||||
m_redis(parRedis)
|
||||
SubmitPasteResponse::SubmitPasteResponse (const IniFile& parIni) :
|
||||
Response(Response::ContentType, "text/plain", "paste", parIni, true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -56,17 +55,14 @@ namespace tawashi {
|
|||
}
|
||||
|
||||
boost::optional<std::string> SubmitPasteResponse::submit_to_redis (const std::string& parText) const {
|
||||
if (not m_redis.is_connected()) {
|
||||
m_redis.connect();
|
||||
m_redis.wait_for_connect();
|
||||
if (not m_redis.is_connected())
|
||||
return boost::optional<std::string>();
|
||||
}
|
||||
auto& redis = this->redis();
|
||||
if (not redis.is_connected())
|
||||
return boost::optional<std::string>();
|
||||
|
||||
const auto next_id = m_redis.incr("paste_counter");
|
||||
const auto next_id = redis.incr("paste_counter");
|
||||
const std::string token = num_to_token(next_id);
|
||||
assert(not token.empty());
|
||||
if (m_redis.set(token, parText)) {
|
||||
if (redis.set(token, parText)) {
|
||||
return boost::make_optional(token);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -21,21 +21,16 @@
|
|||
#include <string>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace redis {
|
||||
class IncRedis;
|
||||
} //namespace redis
|
||||
|
||||
namespace tawashi {
|
||||
class SubmitPasteResponse : public Response {
|
||||
public:
|
||||
SubmitPasteResponse (redis::IncRedis& parRedis, const boost::string_ref& parBaseURI);
|
||||
explicit SubmitPasteResponse (const IniFile& parIni);
|
||||
|
||||
private:
|
||||
virtual void on_process() override;
|
||||
virtual void on_send (std::ostream& parStream) override;
|
||||
boost::optional<std::string> submit_to_redis (const std::string& parText) const;
|
||||
|
||||
redis::IncRedis& m_redis;
|
||||
std::string m_error_message;
|
||||
};
|
||||
} //namespace tawashi
|
||||
|
|
Loading…
Reference in a new issue