2019-03-19 04:30:04 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
|
|
|
|
2019-03-25 00:35:21 +01:00
|
|
|
#include "../external/json.hpp"
|
2019-03-19 04:30:04 +01:00
|
|
|
#include <boost/asio.hpp>
|
|
|
|
#include <boost/beast/core.hpp>
|
|
|
|
#include <boost/beast/http.hpp>
|
|
|
|
#include <boost/beast/version.hpp>
|
2019-03-22 06:47:18 +01:00
|
|
|
#include <boost/format.hpp>
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-04-02 05:28:10 +02:00
|
|
|
#include "swarm.h"
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
template <typename T>
|
|
|
|
class ChannelEncryption;
|
|
|
|
|
|
|
|
namespace http = boost::beast::http; // from <boost/beast/http.hpp>
|
|
|
|
|
|
|
|
using request_t = http::request<http::string_body>;
|
2019-03-31 08:50:19 +02:00
|
|
|
using response_t = http::response<http::string_body>;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-04-12 08:04:19 +02:00
|
|
|
namespace service_node {
|
|
|
|
namespace storage {
|
|
|
|
class Item;
|
|
|
|
}
|
|
|
|
} // namespace service_node
|
|
|
|
|
|
|
|
using service_node::storage::Item;
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
namespace loki {
|
2019-04-02 05:28:10 +02:00
|
|
|
using swarm_callback_t = std::function<void(const all_swarms_t&)>;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-04-12 08:04:19 +02:00
|
|
|
class message_t;
|
|
|
|
|
2019-04-10 09:15:45 +02:00
|
|
|
enum class SNodeError { NO_ERROR, ERROR_OTHER, NO_REACH };
|
2019-04-08 04:20:48 +02:00
|
|
|
|
|
|
|
struct sn_response_t {
|
2019-04-10 09:15:45 +02:00
|
|
|
SNodeError error_code;
|
|
|
|
std::shared_ptr<std::string> body;
|
2019-04-08 04:20:48 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
using http_callback_t = std::function<void(sn_response_t)>;
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
void make_http_request(boost::asio::io_context& ioc, std::string ip,
|
2019-04-10 09:15:45 +02:00
|
|
|
uint16_t port, const request_t& req,
|
|
|
|
http_callback_t&& cb);
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
void make_http_request(boost::asio::io_context& ioc, std::string ip,
|
|
|
|
uint16_t port, std::string target, std::string body,
|
2019-04-08 08:59:02 +02:00
|
|
|
http_callback_t&& cb);
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-04-10 09:15:45 +02:00
|
|
|
void request_swarm_update(boost::asio::io_context& ioc,
|
|
|
|
const swarm_callback_t&& cb);
|
2019-04-02 05:28:10 +02:00
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
class HttpClientSession
|
|
|
|
: public std::enable_shared_from_this<HttpClientSession> {
|
|
|
|
|
|
|
|
using tcp = boost::asio::ip::tcp;
|
|
|
|
|
|
|
|
boost::asio::io_context& ioc_;
|
2019-04-10 07:57:40 +02:00
|
|
|
tcp::socket socket_;
|
|
|
|
tcp::endpoint endpoint_;
|
|
|
|
http_callback_t callback_;
|
|
|
|
boost::asio::steady_timer deadline_timer_;
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
boost::beast::flat_buffer buffer_;
|
|
|
|
request_t req_;
|
2019-03-31 08:50:19 +02:00
|
|
|
response_t res_;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
bool used_callback_ = false;
|
|
|
|
|
2019-04-10 07:57:40 +02:00
|
|
|
void on_connect();
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
void on_write(boost::system::error_code ec, std::size_t bytes_transferred);
|
|
|
|
|
|
|
|
void on_read(boost::system::error_code ec, std::size_t bytes_transferred);
|
|
|
|
|
2019-04-18 03:29:26 +02:00
|
|
|
void trigger_callback(SNodeError error,
|
|
|
|
std::shared_ptr<std::string>&& body);
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
// Resolver and socket require an io_context
|
2019-04-10 07:57:40 +02:00
|
|
|
HttpClientSession(boost::asio::io_context& ioc, const tcp::endpoint& ep,
|
2019-04-17 07:14:37 +02:00
|
|
|
const request_t& req, http_callback_t&& cb);
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-04-10 07:57:40 +02:00
|
|
|
// initiate the client connection
|
|
|
|
void start();
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
~HttpClientSession();
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace http_server {
|
|
|
|
|
|
|
|
class connection_t : public std::enable_shared_from_this<connection_t> {
|
|
|
|
|
|
|
|
using tcp = boost::asio::ip::tcp;
|
|
|
|
|
|
|
|
private:
|
|
|
|
boost::asio::io_context& ioc_;
|
|
|
|
|
|
|
|
// The socket for the currently connected client.
|
|
|
|
tcp::socket socket_;
|
|
|
|
|
|
|
|
// The buffer for performing reads.
|
|
|
|
boost::beast::flat_buffer buffer_{8192};
|
|
|
|
|
|
|
|
// The request message.
|
2019-03-31 08:50:19 +02:00
|
|
|
request_t request_;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
// The response message.
|
2019-03-31 08:50:19 +02:00
|
|
|
response_t response_;
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-04-09 09:17:04 +02:00
|
|
|
// whether the response should be sent asyncronously,
|
|
|
|
// as opposed to directly after connection_t::process_request
|
|
|
|
bool delay_response_ = false;
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
/// TODO: move these if possible
|
|
|
|
std::map<std::string, std::string> header_;
|
|
|
|
|
|
|
|
// The timer for putting a deadline on connection processing.
|
2019-04-09 09:17:04 +02:00
|
|
|
boost::asio::steady_timer deadline_;
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
ServiceNode& service_node_;
|
|
|
|
|
|
|
|
ChannelEncryption<std::string>& channelCipher_;
|
|
|
|
|
|
|
|
std::stringstream bodyStream_;
|
|
|
|
|
2019-04-12 08:04:19 +02:00
|
|
|
// Note that we are only sending a single message through the
|
|
|
|
// notification mechanism. If we somehow accumulated multiple
|
|
|
|
// messages before notification event happens (unlikely), the
|
|
|
|
// following messages will be delivered with the client's
|
|
|
|
// consequent (and immediate) retrieve request
|
|
|
|
struct notification_context_t {
|
|
|
|
// The timer used for internal db polling
|
|
|
|
boost::asio::steady_timer timer;
|
|
|
|
// the message is stored here momentarily; needed because
|
|
|
|
// we can't pass it using current notification mechanism
|
|
|
|
boost::optional<message_t> message;
|
|
|
|
} notification_ctx_;
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
public:
|
|
|
|
connection_t(boost::asio::io_context& ioc, tcp::socket socket,
|
2019-03-19 04:47:55 +01:00
|
|
|
ServiceNode& sn,
|
|
|
|
ChannelEncryption<std::string>& channelEncryption);
|
2019-03-19 04:30:04 +01:00
|
|
|
|
|
|
|
~connection_t();
|
|
|
|
|
|
|
|
/// Initiate the asynchronous operations associated with the connection.
|
|
|
|
void start();
|
|
|
|
|
2019-04-12 08:04:19 +02:00
|
|
|
void notify(const message_t& msg);
|
|
|
|
|
2019-04-16 07:42:36 +02:00
|
|
|
/// "Reset" the connection by sending an empty message list
|
|
|
|
void reset();
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
private:
|
|
|
|
/// Asynchronously receive a complete request message.
|
|
|
|
void read_request();
|
|
|
|
|
2019-04-09 09:17:04 +02:00
|
|
|
/// Check the database for new data, reschedule if empty
|
2019-04-12 08:04:19 +02:00
|
|
|
void poll_db(const std::string& pk, const std::string& last_hash);
|
2019-04-09 09:17:04 +02:00
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
/// Determine what needs to be done with the request message
|
|
|
|
/// (synchronously).
|
|
|
|
void process_request();
|
|
|
|
|
2019-03-22 03:03:21 +01:00
|
|
|
void process_store(const nlohmann::json& params);
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-22 03:03:21 +01:00
|
|
|
void process_retrieve(const nlohmann::json& params);
|
2019-03-19 04:30:04 +01:00
|
|
|
|
2019-03-22 03:03:21 +01:00
|
|
|
void process_snodes_by_pk(const nlohmann::json& params);
|
2019-03-21 06:51:03 +01:00
|
|
|
|
2019-03-22 06:47:18 +01:00
|
|
|
void process_retrieve_all();
|
|
|
|
|
2019-04-12 08:04:19 +02:00
|
|
|
template <typename T>
|
|
|
|
void respond_with_messages(const std::vector<T>& messages);
|
|
|
|
|
2019-03-19 04:30:04 +01:00
|
|
|
/// Asynchronously transmit the response message.
|
|
|
|
void write_response();
|
|
|
|
|
|
|
|
/// Syncronously (?) process client store/load requests
|
|
|
|
void process_client_req();
|
|
|
|
|
|
|
|
// Check whether we have spent enough time on this connection.
|
|
|
|
void register_deadline();
|
|
|
|
|
|
|
|
/// TODO: should move somewhere else
|
2019-03-19 04:47:55 +01:00
|
|
|
template <typename T>
|
|
|
|
bool parse_header(T key_list);
|
2019-04-03 03:08:36 +02:00
|
|
|
|
2019-04-03 06:38:37 +02:00
|
|
|
void handle_wrong_swarm(const std::string& pubKey);
|
2019-03-19 04:30:04 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
void run(boost::asio::io_context& ioc, std::string& ip, uint16_t port,
|
|
|
|
ServiceNode& sn, ChannelEncryption<std::string>& channelEncryption);
|
|
|
|
|
|
|
|
} // namespace http_server
|
|
|
|
|
|
|
|
} // namespace loki
|