Giving code some initial structure

This commit is contained in:
King_DuckZ 2020-06-20 01:27:47 +02:00
parent e0611ec6ff
commit 96e35a5814
7 changed files with 194 additions and 57 deletions

View file

@ -1,63 +1,16 @@
#define HAS_UNCAUGHT_EXCEPTIONS 1
#include <restc-cpp/restc-cpp.h>
#include <restc-cpp/RequestBuilder.h>
#include <string>
#include <boost/fusion/adapted.hpp>
#include "oro/api.hpp"
#include <iostream>
#include "date/date.h"
namespace rc = restc_cpp;
namespace oro {
typedef date::sys_time<std::chrono::microseconds> timestamp_t;
struct Timestamp {
Timestamp& operator= (const std::string& str) {
std::istringstream iss(str);
date::from_stream(iss, "%FT%T%Ez", ts);
return *this;
}
timestamp_t ts;
};
struct Ping {
Timestamp generation_timestamp;
std::string message;
int version;
};
} //namespace oro
BOOST_FUSION_ADAPT_STRUCT(
oro::Ping,
(oro::Timestamp, generation_timestamp)
(std::string, message)
(int, version)
)
int main() {
using date::operator<<;
oro::Api oro_api("https://api.originsro.org", "RESTC_CPP", "Testing");
auto ping = oro_api.ping();
auto rest_client = rc::RestClient::Create();
oro::Ping ping = rest_client->ProcessWithPromiseT<oro::Ping>([&](rc::Context& ctx) {
oro::Ping ping;
std::unique_ptr<rc::Reply> reply = rc::RequestBuilder(ctx)
.Get("https://api.originsro.org/api/v1/ping")
.Header("X-Client", "RESTC_CPP")
.Header("X-Client-Purpose", "Testing")
.Execute();
std::cout << "I got X-RateLimit-Limit: " << *reply->GetHeader("X-RateLimit-Limit") << '\n';
rc::SerializeFromJson(ping, std::move(reply));
return ping;
}).get();
std::cout << "Response received:\n\ttimestamp: " << ping.generation_timestamp.ts;
std::cout << "\n\tmessage: " << ping.message;
std::cout << "\n\tversion: " << ping.version;
std::cout << std::endl;
std::cout << "rate limit: " << ping.first.rate_limit << '\n';
std::cout << "remaining: " << ping.first.rate_limit_remaining << '\n';
std::cout << "reset: " << ping.first.rate_limit_reset << '\n';
std::cout << "retry after: " << ping.first.retry_after << '\n';
std::cout << "server: " << ping.first.server << '\n';
std::cout << "answer: " << ping.second.message << '\n';
std::cout << "version: " << ping.second.version << '\n';
return 0;
}

View file

@ -7,6 +7,8 @@ restc_cpp_dep = dependency('restc-cpp', version: '>=0.1.1',
executable(meson.project_name(),
'main.cpp',
'oro/datatypes.cpp',
'oro/api.cpp',
install: true,
dependencies: [restc_cpp_dep],
include_directories: date_incdir,

75
src/oro/api.cpp Normal file
View file

@ -0,0 +1,75 @@
#include "api.hpp"
#include "datatypes.hpp"
#include <restc-cpp/restc-cpp.h>
#include <restc-cpp/RequestBuilder.h>
#include <boost/fusion/adapted.hpp>
namespace rc = restc_cpp;
BOOST_FUSION_ADAPT_STRUCT(
oro::Ping,
(oro::Timestamp, generation_timestamp)
(std::string, message)
(int, version)
)
namespace oro {
namespace {
constexpr const char g_endpoint_ping[] = "api/v1/ping";
template <typename T>
std::pair<Header, T> call_rest_api (
rc::RestClient& rest_client,
const std::string& url,
const std::string& client_name,
const std::string& client_purpose
) {
return rest_client.template ProcessWithPromiseT< std::pair<Header, T> >([&](rc::Context& ctx) {
std::unique_ptr<rc::Reply> reply = rc::RequestBuilder(ctx)
.Get(url)
.Header("X-Client", client_name)
.Header("X-Client-Purpose", client_purpose)
.Execute();
Header h;
if (auto val = reply->GetHeader("X-RateLimit-Limit")) {
h.rate_limit = std::stoi(*val);
}
if (auto val = reply->GetHeader("X-RateLimit-Remaining")) {
h.rate_limit_remaining = std::stoi(*val);
}
if (auto val = reply->GetHeader("X-RateLimit-Reset")) {
h.rate_limit_reset = std::stoul(*val);
}
if (auto val = reply->GetHeader("Retry-After")) {
h.retry_after = std::stoul(*val);
}
if (auto val = reply->GetHeader("Server")) {
h.server = std::move(*val);
}
T retval;
rc::SerializeFromJson(retval, std::move(reply));
return std::make_pair(std::move(h), std::move(retval));
}).get();
}
} //unnamed namespace
Api::Api (std::string&& root_address, std::string&& client_name, std::string&& client_purpose) :
m_prefix(std::move(root_address)),
m_client_name(std::move(client_name)),
m_client_purpose(std::move(client_purpose)),
m_client(rc::RestClient::Create())
{
if (not m_prefix.empty() and m_prefix[m_prefix.size() - 1] != '/')
m_prefix.push_back('/');
}
Api::~Api() noexcept = default;
std::pair<Header, Ping> Api::ping() {
return call_rest_api<oro::Ping>(*m_client, m_prefix + g_endpoint_ping, m_client_name, m_client_purpose);
}
} //namespace oro

65
src/oro/api.hpp Normal file
View file

@ -0,0 +1,65 @@
#pragma once
#include "ping.hpp"
#include <string>
#include <utility>
#include <memory>
namespace restc_cpp {
class RestClient;
} //namespace restc_cpp
namespace oro {
struct Header {
//Date: Fri, 19 Jun 2020 22:33:43 GMT
Timestamp date;
//Content-Type: application/json
//Content-Length: 89
//Connection: keep-alive
//Set-Cookie: __cfduid=dccdd965b47650be8b0107bb1292154981592606023; expires=Sun, 19-Jul-20 22:33:43 GMT; path=/; domain=.originsro.org; HttpOnly; SameSite=Lax
//X-RateLimit-Limit: 2
int rate_limit;
//X-RateLimit-Remaining: 0
int rate_limit_remaining;
//X-RateLimit-Reset: 1592606027
unsigned long rate_limit_reset;
//Retry-After: 3
unsigned long retry_after;
//CF-Cache-Status: DYNAMIC
//cf-request-id: 03705077e200000091668c6200000001
//Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
//Server: cloudflare
std::string server;
//CF-RAY: 5a60b69fdc270091-LHR
};
class Api {
public:
Api (
std::string&& root_address,
std::string&& client_name,
std::string&& client_purpose
);
~Api() noexcept;
std::pair<Header, Ping> ping();
private:
std::string m_prefix;
std::string m_client_name;
std::string m_client_purpose;
std::unique_ptr<restc_cpp::RestClient> m_client;
};
} //namespace oro

15
src/oro/datatypes.cpp Normal file
View file

@ -0,0 +1,15 @@
#include "datatypes.hpp"
#define HAS_UNCAUGHT_EXCEPTIONS 1
#include "date/date.h"
#include <sstream>
namespace oro {
Timestamp& Timestamp::operator= (const std::string& str) {
std::istringstream iss(str);
//date has this format: 2020-06-19T22:33:36.855672+00:00
date::from_stream(iss, "%FT%T%Ez", ts);
return *this;
}
} //namespace oro

15
src/oro/datatypes.hpp Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include <chrono>
#include <string>
namespace oro {
typedef std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds> timestamp_t;
struct Timestamp {
Timestamp& operator= (const std::string& str);
operator timestamp_t() const { return ts; }
timestamp_t ts;
};
} //namespace oro

12
src/oro/ping.hpp Normal file
View file

@ -0,0 +1,12 @@
#pragma once
#include "datatypes.hpp"
#include <string>
namespace oro {
struct Ping {
Timestamp generation_timestamp;
std::string message;
int version;
};
} //namespace oro