diff --git a/src/nap/page_fetch.cpp b/src/nap/page_fetch.cpp index e2fc270..aae8eed 100644 --- a/src/nap/page_fetch.cpp +++ b/src/nap/page_fetch.cpp @@ -39,18 +39,20 @@ namespace { std::tuple, std::string_view, std::string_view> make_raw_string ( const std::ostringstream& head, - const std::ostringstream& body + const std::ostringstream& body, + std::size_t body_padding ) { //TODO: use .view() with c++20 auto head_str = head.str(); auto body_str = body.str(); - const std::size_t size = head_str.size() + 1 + body_str.size(); + const std::size_t size = head_str.size() + 1 + body_str.size() + body_padding; auto ret = std::make_unique(size); std::copy(head_str.begin(), head_str.end(), ret.get()); ret[head_str.size()] = '\n'; std::copy(body_str.begin(), body_str.end(), ret.get() + head_str.size() + 1); + std::fill(ret.get() + size - body_padding, ret.get() + size, ' '); const char* const buff = ret.get(); return std::make_tuple( @@ -64,7 +66,8 @@ namespace { HttpResponse page_fetch ( const std::string& url, const std::string& user_agent, - const PageFetchHeaders& headers + const PageFetchHeaders& headers, + std::size_t body_padding ) { using curl::curl_pair; @@ -100,7 +103,7 @@ HttpResponse page_fetch ( std::string_view head; { - auto [raw, head_tmp, body] = make_raw_string(header_oss, body_oss); + auto [raw, head_tmp, body] = make_raw_string(header_oss, body_oss, body_padding); head = head_tmp; resp.raw = std::move(raw); resp.body = body; diff --git a/src/nap/private/page_fetch.hpp b/src/nap/private/page_fetch.hpp index d69c5dd..c9a1d24 100644 --- a/src/nap/private/page_fetch.hpp +++ b/src/nap/private/page_fetch.hpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace nap { @@ -29,7 +30,8 @@ typedef std::vector PageFetchHeaders; HttpResponse page_fetch ( const std::string& url, const std::string& user_agent, - const PageFetchHeaders& headers + const PageFetchHeaders& headers, + std::size_t body_padding ); } //namespace nap diff --git a/src/nap/quick_rest.cpp b/src/nap/quick_rest.cpp index 166c1de..3672b4e 100644 --- a/src/nap/quick_rest.cpp +++ b/src/nap/quick_rest.cpp @@ -21,6 +21,11 @@ namespace nap { +QuickRest::QuickRest (std::size_t body_padding) : + m_body_padding(body_padding) +{ +} + void QuickRest::add_headers (std::initializer_list headers) { m_header_lines.reserve(m_header_lines.size() + headers.size()); @@ -39,6 +44,6 @@ void QuickRest::set_user_agent (std::string&& name) { } HttpResponse QuickRest::fetch (std::string_view url) { - return page_fetch(std::string(url), m_user_agent, m_header_lines); + return page_fetch(std::string(url), m_user_agent, m_header_lines, m_body_padding); } } //namespace nap diff --git a/src/nap/quick_rest.hpp b/src/nap/quick_rest.hpp index dc74682..b03d353 100644 --- a/src/nap/quick_rest.hpp +++ b/src/nap/quick_rest.hpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace nap { @@ -31,7 +32,7 @@ class QuickRest { public: typedef std::pair HeaderPairView; - QuickRest() = default; + explicit QuickRest(std::size_t body_padding=0); void add_headers (std::initializer_list headers); void set_user_agent (std::string&& name); @@ -40,6 +41,7 @@ public: private: std::string m_user_agent; std::vector m_header_lines; + std::size_t m_body_padding; }; } //namespace nap diff --git a/src/oro/api_nap.cpp b/src/oro/api_nap.cpp index 83a1cf2..25ed725 100644 --- a/src/oro/api_nap.cpp +++ b/src/oro/api_nap.cpp @@ -17,9 +17,35 @@ #include "private/api_nap.hpp" #include "private/v1_endpoints.hpp" +#include "private/dateconv.hpp" +#include "duckhandy/int_conv.hpp" namespace oro { +namespace { +Header to_header (const nap::HttpResponse& resp) { + using dhandy::int_conv; + + Header ret; + for (const auto& entry : resp.header) { + if (entry.first == "Date") + ret.date = from_header_timestamp(entry.second); + else if (entry.first == "X-RateLimit-Limit") + ret.rate_limit = int_conv(entry.second); + else if (entry.first == "X-RateLimit-Remaining") + ret.rate_limit_remaining = int_conv(entry.second); + else if (entry.first == "X-RateLimit-Reset") + ret.rate_limit_reset = int_conv(entry.second); + else if (entry.first == "Retry-After") + ret.retry_after = int_conv(entry.second); + else if (entry.first == "Server") + ret.server = std::string(entry.second); + } + return ret; +} + +} //unnamed namespace + ApiNap::ApiNap ( std::string&& root_address, std::string&& api_key, @@ -27,7 +53,7 @@ ApiNap::ApiNap ( std::string&& client_purpose ) : Api(std::move(root_address), std::move(api_key), std::move(client_name), std::move(client_purpose)), - m_qrest() + m_qrest(simdjson::SIMDJSON_PADDING) { m_qrest.add_headers({ {"X-Client", m_client_name}, @@ -40,8 +66,22 @@ ApiNap::ApiNap ( ApiNap::~ApiNap() noexcept = default; std::pair ApiNap::ping() { - m_qrest.fetch(m_prefix + g_endpoint_ping); - //std::cout << nap::page_fetch(url, client_name).body << '\n'; + auto resp = m_qrest.fetch(m_prefix + g_endpoint_ping); + + Ping dataret; + { + std::unique_lock lock(m_json_mutex); + simdjson::dom::element doc = m_json.parse( + reinterpret_cast(resp.body.data()), + resp.body.size() + ); + + dataret.message = doc["message"]; + dataret.generation_timestamp = std::string(doc["generation_timestamp"]); + dataret.version = static_cast(int64_t(doc["version"])); + } + + return {to_header(resp), std::move(dataret)}; } std::pair ApiNap::who_am_i() { diff --git a/src/oro/private/api_nap.hpp b/src/oro/private/api_nap.hpp index d8bbb52..935429f 100644 --- a/src/oro/private/api_nap.hpp +++ b/src/oro/private/api_nap.hpp @@ -19,6 +19,7 @@ #include "oro/api.hpp" #include "nap/quick_rest.hpp" +#include namespace oro { @@ -41,6 +42,8 @@ public: virtual std::pair fame_list() override; private: + std::mutex m_json_mutex; + simdjson::dom::parser m_json; nap::QuickRest m_qrest; }; diff --git a/src/oro/private/dateconv.cpp b/src/oro/private/dateconv.cpp index 777929d..911ad1e 100644 --- a/src/oro/private/dateconv.cpp +++ b/src/oro/private/dateconv.cpp @@ -32,8 +32,8 @@ namespace { } }; - Timestamp to_timestamp (const char* fmt, const std::string& str) { - std::istringstream iss(str); + Timestamp to_timestamp (const char* fmt, std::string_view str) { + std::istringstream iss{std::string(str)}; Timestamp ts; date::from_stream(iss, fmt, ts.ts); return ts; @@ -57,6 +57,10 @@ Timestamp from_json_timestamp (const std::string& str) { } Timestamp from_header_timestamp (const std::string& str) { + return from_header_timestamp(std::string_view(str)); +} + +Timestamp from_header_timestamp (std::string_view str) { UniqueLocale loc(std::setlocale(LC_TIME, "POSIX")); //date has this format: Fri, 19 Jun 2020 22:33:43 GMT return to_timestamp("%a, %d %b %Y %T %Z", str); diff --git a/src/oro/private/dateconv.hpp b/src/oro/private/dateconv.hpp index 75815c5..361f137 100644 --- a/src/oro/private/dateconv.hpp +++ b/src/oro/private/dateconv.hpp @@ -19,9 +19,11 @@ #include "oro/datatypes.hpp" #include +#include namespace oro { Timestamp from_json_timestamp (const std::string& str); +Timestamp from_header_timestamp (std::string_view str); Timestamp from_header_timestamp (const std::string& str); Timestamp from_sqlite_timestamp (const std::string& str); std::string to_sqlite_string (const Timestamp& ts);