Initial version of a rest server
This is more of a proof of concept than the actual feature. WiP
This commit is contained in:
parent
22ae50b59f
commit
a2ab75b18d
14 changed files with 210 additions and 3 deletions
|
@ -16,3 +16,6 @@ items=604800
|
|||
icons=604800
|
||||
shops=120
|
||||
creators=400
|
||||
|
||||
[webserver]
|
||||
enabled=yes
|
||||
|
|
|
@ -54,6 +54,10 @@ namespace {
|
|||
constexpr const char g_store_raw_json[] = "store_raw_json";
|
||||
constexpr const char g_store_raw_json_def[] = "false";
|
||||
|
||||
constexpr const char g_enable_webserver_sect[] = "webserver";
|
||||
constexpr const char g_enable_webserver[] = "enabled";
|
||||
constexpr const char g_enable_webserver_def[] = "no";
|
||||
|
||||
constexpr const char g_json_store_mode_sect[] = "options";
|
||||
constexpr const char g_json_store_mode[] = "json_store_mode";
|
||||
constexpr const char g_json_store_mode_def[] = "plain";
|
||||
|
@ -197,6 +201,11 @@ bool AppConfig::store_raw_json() const {
|
|||
return to_bool(val);
|
||||
}
|
||||
|
||||
bool AppConfig::enable_webserver() const {
|
||||
std::string_view val = value_ifp(m_ini, g_enable_webserver_sect, g_enable_webserver, g_enable_webserver_def, false);
|
||||
return to_bool(val);
|
||||
}
|
||||
|
||||
std::size_t AppConfig::items_timeout() const {
|
||||
std::string_view val = value_ifp(m_ini, g_items_time_sect, g_items_time, g_items_time_def, false);
|
||||
return std::max(dhandy::int_conv<std::size_t>(val), g_min_update_timeout);
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
std::size_t fetch_extra_delay() const;
|
||||
std::string_view backend() const;
|
||||
bool store_raw_json() const;
|
||||
bool enable_webserver() const;
|
||||
|
||||
std::size_t items_timeout() const;
|
||||
std::size_t icons_timeout() const;
|
||||
|
|
|
@ -30,6 +30,7 @@ constexpr const unsigned short int g_version_minor = @PROJECT_VERSION_MINOR@;
|
|||
constexpr const unsigned short int g_version_patch = @PROJECT_VERSION_PATCH@;
|
||||
|
||||
#mesondefine OROTOOL_WITH_LZMA
|
||||
#mesondefine OROTOOL_WITH_WEBSERVER
|
||||
|
||||
#mesondefine OROTOOL_WITH_SQLITE
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#include "app_config.hpp"
|
||||
#include "duckhandy/int_conv.hpp"
|
||||
#include "duckhandy/string_bt.hpp"
|
||||
#if defined(OROTOOL_WITH_WEBSERVER)
|
||||
# include "webserver/rest_server.hpp"
|
||||
#endif
|
||||
#if !defined(NDEBUG)
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
@ -97,6 +100,8 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
std::unique_ptr<oro::OriginsDB> db(oro::OriginsDB::make(app_conf.backend(), app_conf.db_path()));
|
||||
|
||||
duck::RestServer server(8171);
|
||||
|
||||
duck::test(oro_api.get(), db.get(), app_conf);
|
||||
}
|
||||
#if defined(OROTOOL_WITH_RESTCCPP)
|
||||
|
|
|
@ -28,6 +28,7 @@ civetweb_dep = dependency('civetweb', version: '>=1.12',
|
|||
'civetweb_enable_server_executable=false',
|
||||
'civetweb_enable_cgi=false',
|
||||
'civetweb_enable_caching=true',
|
||||
'default_library=static',
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -77,6 +78,7 @@ conf.set('OROTOOL_WITH_SQLITE', sqlitecpp_dep.found())
|
|||
conf.set('OROTOOL_WITH_LZMA', lzma_dep.found())
|
||||
conf.set('OROTOOL_WITH_NAP', get_option('rest_lib') == 'nap')
|
||||
conf.set('OROTOOL_WITH_RESTCCPP', get_option('rest_lib') == 'restc-cpp')
|
||||
conf.set('OROTOOL_WITH_WEBSERVER', civetweb_dep.found())
|
||||
project_config_file = configure_file(
|
||||
input: 'config.hpp.in',
|
||||
output: meson.project_name() + '_config.hpp',
|
||||
|
@ -125,6 +127,10 @@ if lzma_dep.found()
|
|||
optional_sources += ['lzma.cpp']
|
||||
endif
|
||||
|
||||
if civetweb_dep.found()
|
||||
optional_sources += ['webserver/rest_server.cpp']
|
||||
endif
|
||||
|
||||
executable(meson.project_name(),
|
||||
'main.cpp',
|
||||
'ini_file.cpp',
|
||||
|
@ -152,6 +158,7 @@ executable(meson.project_name(),
|
|||
optional_sources,
|
||||
project_config_file,
|
||||
'eventia_thread_pool.cpp',
|
||||
'webserver/private/dateconv.cpp',
|
||||
install: true,
|
||||
dependencies: lib_deps,
|
||||
include_directories: [
|
||||
|
|
|
@ -27,6 +27,14 @@ namespace oro {
|
|||
return *this;
|
||||
}
|
||||
|
||||
Timestamp Timestamp::now() {
|
||||
return Timestamp{
|
||||
std::chrono::time_point_cast<oro::timestamp_t::duration>(
|
||||
std::chrono::system_clock::now()
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Timestamp& ts) {
|
||||
using date::operator<<;
|
||||
os << ts.ts;
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace oro {
|
|||
struct Timestamp {
|
||||
Timestamp& operator= (std::string&& str);
|
||||
operator timestamp_t() const { return ts; }
|
||||
static Timestamp now();
|
||||
|
||||
timestamp_t ts;
|
||||
};
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace {
|
|||
oro::Timestamp calc_next_update (const oro::Header& header, double min_wait, double extra) {
|
||||
oro::Timestamp ret;
|
||||
ret.ts =
|
||||
std::chrono::time_point_cast<oro::timestamp_t::duration>(std::chrono::system_clock::now()) +
|
||||
oro::Timestamp::now().ts +
|
||||
std::chrono::seconds(time_interval(header, min_wait, extra));
|
||||
return ret;
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ oro::OriginsDB& TimerBase::db() {
|
|||
void TimerBase::reset_db_access_time (oro::DBOperation op) {
|
||||
oro::Timestamp ts;
|
||||
ts.ts =
|
||||
std::chrono::time_point_cast<oro::timestamp_t::duration>(std::chrono::system_clock::now()) +
|
||||
oro::Timestamp::now().ts +
|
||||
std::chrono::seconds(static_cast<unsigned long>(m_min_wait));
|
||||
db().update_access_time(ts, op);
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ inline void TimerOroApi<Op>::fetch_data (oro::SourceFormat store_mode) {
|
|||
m_retries_left = error_retries();
|
||||
if (429 == status_code) {
|
||||
oro::Header head;
|
||||
head.date.ts = std::chrono::time_point_cast<oro::timestamp_t::duration>(std::chrono::system_clock::now());
|
||||
head.date.ts = oro::Timestamp::now().ts;
|
||||
head.rate_limit = 1;
|
||||
head.rate_limit_remaining = 0;
|
||||
head.rate_limit_reset = 600;
|
||||
|
|
34
src/webserver/private/dateconv.cpp
Normal file
34
src/webserver/private/dateconv.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of orotool.
|
||||
*
|
||||
* Orotool 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.
|
||||
*
|
||||
* Orotool 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 Orotool. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dateconv.hpp"
|
||||
|
||||
#define HAS_UNCAUGHT_EXCEPTIONS 1
|
||||
#include "date/date.h"
|
||||
|
||||
namespace duck {
|
||||
|
||||
std::string to_header_string (const oro::Timestamp& ts) {
|
||||
using date::operator<<;
|
||||
using std::chrono::seconds;
|
||||
using date::floor;
|
||||
using date::format;
|
||||
|
||||
return format("%a, %d %b %Y %T %Z", floor<seconds>(ts.ts));
|
||||
}
|
||||
|
||||
} //namespace duck
|
25
src/webserver/private/dateconv.hpp
Normal file
25
src/webserver/private/dateconv.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of orotool.
|
||||
*
|
||||
* Orotool 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.
|
||||
*
|
||||
* Orotool 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 Orotool. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "oro/datatypes.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace duck {
|
||||
std::string to_header_string (const oro::Timestamp& ts);
|
||||
} //namespace duck
|
79
src/webserver/rest_server.cpp
Normal file
79
src/webserver/rest_server.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of orotool.
|
||||
*
|
||||
* Orotool 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.
|
||||
*
|
||||
* Orotool 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 Orotool. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "rest_server.hpp"
|
||||
#include "CivetServer.h"
|
||||
#include "duckhandy/int_conv.hpp"
|
||||
#include "private/dateconv.hpp"
|
||||
|
||||
namespace duck {
|
||||
namespace {
|
||||
class V1ItemsHandler : public CivetHandler {
|
||||
public:
|
||||
bool handleGet (CivetServer* server, struct mg_connection* conn) override {
|
||||
mg_printf(conn,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: application/json; charset=utf-8\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Date: %s\r\n"
|
||||
"\r\n",
|
||||
to_header_string(oro::Timestamp::now()).c_str()
|
||||
);
|
||||
mg_printf(conn, "Hi this is the items handler\r\n");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void init_civetweb_ifn() {
|
||||
static bool initialised = false;
|
||||
if (not initialised) {
|
||||
initialised = true;
|
||||
if (mg_check_feature(2))
|
||||
mg_init_library(MG_FEATURES_SSL);
|
||||
else
|
||||
mg_init_library(0);
|
||||
}
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
struct RestServer::LocalData {
|
||||
explicit LocalData (const char* options[]) :
|
||||
server(options)
|
||||
{
|
||||
server.addHandler("/v1/items", v1_items_handler);
|
||||
}
|
||||
|
||||
V1ItemsHandler v1_items_handler;
|
||||
CivetServer server;
|
||||
};
|
||||
|
||||
RestServer::RestServer (uint16_t port) {
|
||||
init_civetweb_ifn();
|
||||
|
||||
const std::string port_str = dhandy::int_conv<std::string>(port);
|
||||
const char* options[] = {
|
||||
"decode_url", "yes",
|
||||
"listening_ports", port_str.c_str(),
|
||||
"request_timeout_ms", "10000",
|
||||
nullptr
|
||||
};
|
||||
|
||||
m_local = std::make_unique<LocalData>(options);
|
||||
}
|
||||
|
||||
RestServer::~RestServer() noexcept = default;
|
||||
} //namespace duck
|
34
src/webserver/rest_server.hpp
Normal file
34
src/webserver/rest_server.hpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Copyright 2020, Michele Santullo
|
||||
* This file is part of orotool.
|
||||
*
|
||||
* Orotool 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.
|
||||
*
|
||||
* Orotool 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 Orotool. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace duck {
|
||||
class RestServer {
|
||||
public:
|
||||
RestServer (uint16_t port);
|
||||
~RestServer() noexcept;
|
||||
|
||||
private:
|
||||
struct LocalData;
|
||||
|
||||
std::unique_ptr<LocalData> m_local;
|
||||
};
|
||||
} //namespace duck
|
Loading…
Reference in a new issue