Add option to choose between restc-cpp and nap

I don't think this is very clean, but they might fix
the bug in restc-cpp that is currently holding this
project back, and I might want to go back to it.
I might refactor this into a virtual class.
This commit is contained in:
King_DuckZ 2020-08-29 16:42:34 +01:00
parent 8b09d7da53
commit 80bfbc640a
9 changed files with 182 additions and 42 deletions

View file

@ -2,3 +2,4 @@ option('base_url', type: 'string', value: 'https://api.originsro.org')
option('def_sqlite_db_name', type: 'string', value: 'originsro.db3')
option('tests', type: 'feature', value: 'enabled')
option('with_sqlite', type: 'feature', value: 'auto')
option('rest_lib', type: 'combo', choices: ['nap', 'restc-cpp'], value: 'nap')

View file

@ -31,6 +31,9 @@ constexpr const unsigned short int g_version_patch = @PROJECT_VERSION_PATCH@;
#mesondefine OROTOOL_WITH_SQLITE
#mesondefine OROTOOL_WITH_NAP
#mesondefine OROTOOL_WITH_RESTCCPP
#if defined(OROTOOL_WITH_SQLITE)
constexpr const char g_sqlite_backend_name[] = "sqlite";
#endif

View file

@ -23,7 +23,9 @@
#include "duckhandy/int_conv.hpp"
#include "duckhandy/string_bt.hpp"
#include <iostream>
#include <restc-cpp/error.h>
#if defined(OROTOOL_WITH_RESTCCPP)
# include <restc-cpp/error.h>
#endif
namespace {
void print_ping(oro::Api& oro_api) {
@ -83,11 +85,13 @@ int main(int argc, char* argv[]) {
app_conf.worker_threads()
);
}
#if defined(OROTOOL_WITH_RESTCCPP)
catch (const restc_cpp::CommunicationException& err) {
std::cerr << "Communication with server \"" << duck::g_base_url <<
"\" failed: " << err.what() << '\n';
return 1;
}
#endif
catch (const std::exception& err) {
std::cerr << "An error occurred during the program execution: " <<
err.what() << '\n';

View file

@ -1,10 +1,12 @@
restc_cpp_dep = dependency('restc-cpp', version: '>=0.1.1',
if get_option('rest_lib') == 'restc-cpp'
restc_cpp_dep = dependency('restc-cpp', version: '>=0.1.1',
fallback: ['restc-cpp', 'restc_cpp_dep'],
default_options: [
'restc_cpp_with_unit_tests=false',
'restc_cpp_log_with_boost_log=false',
],
)
)
endif
curlcpp_dep = dependency('curlcpp', version: '>=1.4',
fallback: ['curlcpp', 'curlcpp_dep'],
@ -50,6 +52,8 @@ conf.set('PROJECT_VERSION_MAJOR', version_arr[0])
conf.set('PROJECT_VERSION_MINOR', version_arr[1])
conf.set('PROJECT_VERSION_PATCH', version_arr[2])
conf.set('OROTOOL_WITH_SQLITE', sqlitecpp_dep.found())
conf.set('OROTOOL_WITH_NAP', get_option('rest_lib') == 'nap')
conf.set('OROTOOL_WITH_RESTCCPP', get_option('rest_lib') == 'restc-cpp')
project_config_file = configure_file(
input: 'config.hpp.in',
output: meson.project_name() + '_config.hpp',
@ -73,7 +77,6 @@ if not backends_selected
endif
lib_deps = [
restc_cpp_dep,
ev_dep,
threads_dep,
boost_dep,
@ -81,11 +84,22 @@ lib_deps = [
simdjson_dep,
] + backend_libs
if get_option('rest_lib') == 'nap'
oro_rest_sources = [
'nap/page_fetch.cpp',
'nap/http_header_parse.cpp',
'nap/quick_rest.cpp',
'oro/api_nap.cpp',
]
elif get_option('rest_lib') == 'restc-cpp'
oro_rest_sources = ['oro/api_restccpp.cpp']
lib_deps += [restc_cpp_dep]
endif
executable(meson.project_name(),
'main.cpp',
'ini_file.cpp',
'oro/datatypes.cpp',
'oro/api.cpp',
'oro/private/dateconv.cpp',
'oro/items.cpp',
'oro/shops.cpp',
@ -103,9 +117,7 @@ executable(meson.project_name(),
'eventia/event.cpp',
'timer_oro_api.cpp',
'oro/originsdb.cpp',
'nap/page_fetch.cpp',
'nap/http_header_parse.cpp',
'nap/quick_rest.cpp',
oro_rest_sources,
project_config_file,
install: true,
dependencies: lib_deps,

View file

@ -83,12 +83,9 @@ public:
std::pair<Header, Creators> fame_list();
private:
std::string m_prefix;
std::string m_api_key;
std::string m_client_name;
std::string m_client_purpose;
struct LocalData;
std::unique_ptr<restc_cpp::RestClient> m_client;
std::unique_ptr<LocalData> m_local;
};
} //namespace oro

77
src/oro/api_nap.cpp Normal file
View file

@ -0,0 +1,77 @@
/* 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 "api.hpp"
#include "nap/quick_rest.hpp"
#include "private/v1_endpoints.hpp"
namespace oro {
struct Api::LocalData {
LocalData (
std::string&& root_address
) :
prefix(std::move(root_address))
{
}
std::string prefix;
nap::QuickRest qrest;
};
Api::Api (
std::string&& root_address,
std::string&& api_key,
std::string&& client_name,
std::string&& client_purpose
) :
m_local(std::make_unique<LocalData>(std::move(root_address)))
{
if (not m_local->prefix.empty() and m_local->prefix[m_local->prefix.size() - 1] != '/')
m_local->prefix.push_back('/');
m_local->qrest.add_headers({
{"X-Client", client_name},
{"X-Client-Purpose", client_purpose},
{"x-api-key", api_key}
});
m_local->qrest.set_user_agent(std::move(client_name));
}
Api::~Api() noexcept = default;
std::pair<Header, Ping> Api::ping() {
m_local->qrest.fetch(m_local->prefix + g_endpoint_ping);
//std::cout << nap::page_fetch(url, client_name).body << '\n';
}
std::pair<Header, WhoAmI> Api::who_am_i() {
}
std::pair<Header, Items> Api::items_list() {
}
std::pair<Header, Icons> Api::items_icons() {
}
std::pair<Header, Shops> Api::market_list() {
}
std::pair<Header, Creators> Api::fame_list() {
}
} //namespace oro

View file

@ -18,6 +18,7 @@
#include "api.hpp"
#include "datatypes.hpp"
#include "private/dateconv.hpp"
#include "private/v1_endpoints.hpp"
#include <restc-cpp/restc-cpp.h>
#include <restc-cpp/RequestBuilder.h>
#include <boost/fusion/adapted.hpp>
@ -127,12 +128,6 @@ BOOST_FUSION_ADAPT_STRUCT(
namespace oro {
namespace {
constexpr const std::int64_t g_max_json_mem = 1024 * 1024 * 20;
constexpr const char g_endpoint_ping[] = "api/v1/ping";
constexpr const char g_endpoint_whoami[] = "api/v1/whoami";
constexpr const char g_endpoint_items_list[] = "api/v1/items/list";
constexpr const char g_endpoint_items_icons[] = "api/v1/items/icons";
constexpr const char g_endpoint_market_list[] = "api/v1/market/list";
constexpr const char g_endpoint_fame_list[] = "api/v1/fame/list";
template <typename T>
std::pair<Header, T> call_rest_api (
@ -183,26 +178,43 @@ namespace {
}
} //unnamed namespace
struct Api::LocalData {
explicit LocalData (
std::string&& root_address,
std::string&& api_key,
std::string&& client_name,
std::string&& client_purpose
) :
prefix(std::move(root_address)),
api_key(std::move(api_key)),
client_name(std::move(client_name)),
client_purpose(std::move(client_purpose)),
client(rc::RestClient::Create())
{}
std::string prefix;
std::string api_key;
std::string client_name;
std::string client_purpose;
std::unique_ptr<restc_cpp::RestClient> client;
};
Api::Api (
std::string&& root_address,
std::string&& api_key,
std::string&& client_name,
std::string&& client_purpose
) :
m_prefix(std::move(root_address)),
m_api_key(std::move(api_key)),
m_client_name(std::move(client_name)),
m_client_purpose(std::move(client_purpose)),
m_client(rc::RestClient::Create())
m_local(std::make_unique<LocalData>(std::move(root_address), std::move(api_key), std::move(client_name), std::move(client_purpose)))
{
if (not m_prefix.empty() and m_prefix[m_prefix.size() - 1] != '/')
m_prefix.push_back('/');
if (not m_local->prefix.empty() and m_local->prefix[m_local->prefix.size() - 1] != '/')
m_local->prefix.push_back('/');
#if !defined(NDEBUG)
std::cout << "OriginsRO API settings\n" <<
"\troot_address: \"" << m_prefix << "\"\n" <<
"\tapi_key: \"" << m_api_key << "\"\n" <<
"\tclient_name: \"" << m_client_name << "\"\n" <<
"\tclient_purpose: \"" << m_client_purpose << "\"\n" <<
"\troot_address: \"" << m_local->prefix << "\"\n" <<
"\tapi_key: \"" << m_local->api_key << "\"\n" <<
"\tclient_name: \"" << m_local->client_name << "\"\n" <<
"\tclient_purpose: \"" << m_local->client_purpose << "\"\n" <<
"";
#endif
}
@ -210,27 +222,27 @@ Api::Api (
Api::~Api() noexcept = default;
std::pair<Header, Ping> Api::ping() {
return call_rest_api<oro::Ping>(*m_client, m_prefix + g_endpoint_ping, m_api_key, m_client_name, m_client_purpose);
return call_rest_api<oro::Ping>(*m_local->client, m_local->prefix + g_endpoint_ping, m_local->api_key, m_local->client_name, m_local->client_purpose);
}
std::pair<Header, WhoAmI> Api::who_am_i() {
return call_rest_api<oro::WhoAmI>(*m_client, m_prefix + g_endpoint_whoami, m_api_key, m_client_name, m_client_purpose);
return call_rest_api<oro::WhoAmI>(*m_local->client, m_local->prefix + g_endpoint_whoami, m_local->api_key, m_local->client_name, m_local->client_purpose);
}
std::pair<Header, Items> Api::items_list() {
return call_rest_api<oro::Items>(*m_client, m_prefix + g_endpoint_items_list, m_api_key, m_client_name, m_client_purpose);
return call_rest_api<oro::Items>(*m_local->client, m_local->prefix + g_endpoint_items_list, m_local->api_key, m_local->client_name, m_local->client_purpose);
}
std::pair<Header, Icons> Api::items_icons() {
return call_rest_api<oro::Icons>(*m_client, m_prefix + g_endpoint_items_icons, m_api_key, m_client_name, m_client_purpose);
return call_rest_api<oro::Icons>(*m_local->client, m_local->prefix + g_endpoint_items_icons, m_local->api_key, m_local->client_name, m_local->client_purpose);
}
std::pair<Header, Shops> Api::market_list() {
return call_rest_api<oro::Shops>(*m_client, m_prefix + g_endpoint_market_list, m_api_key, m_client_name, m_client_purpose);
return call_rest_api<oro::Shops>(*m_local->client, m_local->prefix + g_endpoint_market_list, m_local->api_key, m_local->client_name, m_local->client_purpose);
}
std::pair<Header, Creators> Api::fame_list() {
return call_rest_api<oro::Creators>(*m_client, m_prefix + g_endpoint_fame_list, m_api_key, m_client_name, m_client_purpose);
return call_rest_api<oro::Creators>(*m_local->client, m_local->prefix + g_endpoint_fame_list, m_local->api_key, m_local->client_name, m_local->client_purpose);
}
} //namespace oro

View file

@ -0,0 +1,29 @@
/* 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
namespace oro {
namespace {
constexpr const char g_endpoint_ping[] = "api/v1/ping";
constexpr const char g_endpoint_whoami[] = "api/v1/whoami";
constexpr const char g_endpoint_items_list[] = "api/v1/items/list";
constexpr const char g_endpoint_items_icons[] = "api/v1/items/icons";
constexpr const char g_endpoint_market_list[] = "api/v1/market/list";
constexpr const char g_endpoint_fame_list[] = "api/v1/fame/list";
} //unnamed namespace
} //namespace oro

View file

@ -16,8 +16,11 @@
*/
#include "timer_oro_api.hpp"
#include "orotool_config.hpp"
#include "oro/api.hpp"
#include <restc-cpp/error.h>
#if defined(OROTOOL_WITH_RESTCCPP)
# include <restc-cpp/error.h>
#endif
#include <exception>
namespace duck {
@ -66,6 +69,7 @@ inline void TimerOroApi<Op>::fetch_data() {
set_next_timer(results.first);
this->update_db(results.second, results.first);
}
#if defined(OROTOOL_WITH_RESTCCPP)
catch (const restc_cpp::RequestFailedWithErrorException& err) {
status_code = err.http_response.status_code;
if (429 == err.http_response.status_code) {
@ -75,6 +79,7 @@ inline void TimerOroApi<Op>::fetch_data() {
throw err;
}
}
#endif
catch (...) {
this->set_exception(std::current_exception());
}