diff --git a/meson_options.txt b/meson_options.txt index 54b5bc8..94ce1f3 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -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') diff --git a/src/config.hpp.in b/src/config.hpp.in index 15135bb..c94cc0a 100644 --- a/src/config.hpp.in +++ b/src/config.hpp.in @@ -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 diff --git a/src/main.cpp b/src/main.cpp index 89766b0..45bce47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,7 +23,9 @@ #include "duckhandy/int_conv.hpp" #include "duckhandy/string_bt.hpp" #include -#include +#if defined(OROTOOL_WITH_RESTCCPP) +# include +#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'; diff --git a/src/meson.build b/src/meson.build index 3856309..21e0914 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,10 +1,12 @@ -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', - ], -) +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, diff --git a/src/oro/api.hpp b/src/oro/api.hpp index fc65026..8ebd436 100644 --- a/src/oro/api.hpp +++ b/src/oro/api.hpp @@ -83,12 +83,9 @@ public: std::pair 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 m_client; + std::unique_ptr m_local; }; } //namespace oro diff --git a/src/oro/api_nap.cpp b/src/oro/api_nap.cpp new file mode 100644 index 0000000..39acc55 --- /dev/null +++ b/src/oro/api_nap.cpp @@ -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 . + */ + +#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(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 Api::ping() { + m_local->qrest.fetch(m_local->prefix + g_endpoint_ping); + //std::cout << nap::page_fetch(url, client_name).body << '\n'; +} + +std::pair Api::who_am_i() { +} + +std::pair Api::items_list() { +} + +std::pair Api::items_icons() { +} + +std::pair Api::market_list() { +} + +std::pair Api::fame_list() { +} + +} //namespace oro diff --git a/src/oro/api.cpp b/src/oro/api_restccpp.cpp similarity index 71% rename from src/oro/api.cpp rename to src/oro/api_restccpp.cpp index e27117a..cd28505 100644 --- a/src/oro/api.cpp +++ b/src/oro/api_restccpp.cpp @@ -18,6 +18,7 @@ #include "api.hpp" #include "datatypes.hpp" #include "private/dateconv.hpp" +#include "private/v1_endpoints.hpp" #include #include #include @@ -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 std::pair 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 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(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 Api::ping() { - return call_rest_api(*m_client, m_prefix + g_endpoint_ping, m_api_key, m_client_name, m_client_purpose); + return call_rest_api(*m_local->client, m_local->prefix + g_endpoint_ping, m_local->api_key, m_local->client_name, m_local->client_purpose); } std::pair Api::who_am_i() { - return call_rest_api(*m_client, m_prefix + g_endpoint_whoami, m_api_key, m_client_name, m_client_purpose); + return call_rest_api(*m_local->client, m_local->prefix + g_endpoint_whoami, m_local->api_key, m_local->client_name, m_local->client_purpose); } std::pair Api::items_list() { - return call_rest_api(*m_client, m_prefix + g_endpoint_items_list, m_api_key, m_client_name, m_client_purpose); + return call_rest_api(*m_local->client, m_local->prefix + g_endpoint_items_list, m_local->api_key, m_local->client_name, m_local->client_purpose); } std::pair Api::items_icons() { - return call_rest_api(*m_client, m_prefix + g_endpoint_items_icons, m_api_key, m_client_name, m_client_purpose); + return call_rest_api(*m_local->client, m_local->prefix + g_endpoint_items_icons, m_local->api_key, m_local->client_name, m_local->client_purpose); } std::pair Api::market_list() { - return call_rest_api(*m_client, m_prefix + g_endpoint_market_list, m_api_key, m_client_name, m_client_purpose); + return call_rest_api(*m_local->client, m_local->prefix + g_endpoint_market_list, m_local->api_key, m_local->client_name, m_local->client_purpose); } std::pair Api::fame_list() { - return call_rest_api(*m_client, m_prefix + g_endpoint_fame_list, m_api_key, m_client_name, m_client_purpose); + return call_rest_api(*m_local->client, m_local->prefix + g_endpoint_fame_list, m_local->api_key, m_local->client_name, m_local->client_purpose); } } //namespace oro diff --git a/src/oro/private/v1_endpoints.hpp b/src/oro/private/v1_endpoints.hpp new file mode 100644 index 0000000..15103d9 --- /dev/null +++ b/src/oro/private/v1_endpoints.hpp @@ -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 . + */ + +#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 diff --git a/src/timer_oro_api.cpp b/src/timer_oro_api.cpp index 8d5f4e0..22a47f2 100644 --- a/src/timer_oro_api.cpp +++ b/src/timer_oro_api.cpp @@ -16,8 +16,11 @@ */ #include "timer_oro_api.hpp" +#include "orotool_config.hpp" #include "oro/api.hpp" -#include +#if defined(OROTOOL_WITH_RESTCCPP) +# include +#endif #include namespace duck { @@ -66,6 +69,7 @@ inline void TimerOroApi::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::fetch_data() { throw err; } } +#endif catch (...) { this->set_exception(std::current_exception()); }