Skip to content

Commit

Permalink
Allow HTTPP to be compiled to use boost promise
Browse files Browse the repository at this point in the history
  • Loading branch information
daedric committed May 6, 2014
1 parent feb4bfa commit b7d9a36
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 40 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ OPTION(BUILD_SHARED_LIBS "Should the shared lib be built")

# Setting vars #################################################################
SET(HTTPP_VERSION_MAJOR "0")
SET(HTTPP_VERSION_MINOR "3")
SET(HTTPP_VERSION_PATCH "3~dev")
SET(HTTPP_VERSION_MINOR "4")
SET(HTTPP_VERSION_PATCH "0~dev")

SET(CPACK_PACKAGE_VERSION_MAJOR ${HTTPP_VERSION_MAJOR})
SET(CPACK_PACKAGE_VERSION_MINOR ${HTTPP_VERSION_MINOR})
Expand Down
5 changes: 3 additions & 2 deletions include/httpp/HttpClient.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
# include <string>
# include <vector>
# include <memory>
# include <future>

# include <boost/asio/io_service.hpp>

# include "detail/config.hpp"
# include "utils/Exception.hpp"
# include "utils/ThreadPool.hpp"
# include "http/Protocol.hpp"
Expand All @@ -38,7 +38,8 @@ class HttpClient
public:
using Request = HTTP::client::Request;
using Response = HTTP::client::Response;
using Future = std::future<Response>;

using Future = detail::Future<Response>;
using CompletionHandler = std::function<void (Future&&)>;

// AsyncHandler is garanteed to be always safe to call
Expand Down
87 changes: 87 additions & 0 deletions include/httpp/detail/config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Part of HTTPP.
*
* Distributed under the 3-clause BSD licence (See LICENCE.TXT file at the
* project root).
*
* Copyright (c) 2014 Thomas Sanchez. All rights reserved.
*
*/

#ifndef _HTTPP__DETAIL_CONFIG_HPP_
# define _HTTPP__DETAIL_CONFIG_HPP_

# include <type_traits>

# define HTTPP_USE_BOOST_PROMISE 1

# if HTTPP_USE_BOOST_PROMISE
# include <boost/thread/future.hpp>
# include <boost/exception/all.hpp>
# define HTTPP_PROMISE_NAMESPACE boost
# else
# include <future>
# define HTTPP_PROMISE_NAMESPACE std
# endif

namespace HTTPP
{

namespace detail
{

template <typename T>
using Promise = HTTPP_PROMISE_NAMESPACE::promise<T>;

template <typename T>
using Future = decltype(std::declval<Promise<T>>().get_future());

# if HTTPP_USE_BOOST_PROMISE

using ExceptionPtr = boost::exception_ptr;

template <typename T>
static inline ExceptionPtr
make_exception_ptr(const T& ex) noexcept(noexcept(boost::copy_exception(ex)))
{
return boost::copy_exception(ex);
}

static inline ExceptionPtr
current_exception() noexcept(noexcept(boost::current_exception()))
{
return boost::current_exception();
}

[[noreturn]] static void inline rethrow_exception(const ExceptionPtr& ex)
{
boost::rethrow_exception(ex);
}

# else

using ExceptionPtr = std::exception_ptr;

template <typename T>
static inline ExceptionPtr make_exception_ptr(const T& ex)
{
return std::make_exception_ptr(ex);
}

static inline ExceptionPtr
current_exception() noexcept(noexcept(std::current_exception()))
{
return std::current_exception();
}

[[noreturn]] static void inline rethrow_exception(const ExceptionPtr& ex)
{
std::rethrow_exception(ex);
}

# endif

} // namespace detail
} // namespace HTTPP

#endif
12 changes: 10 additions & 2 deletions include/httpp/utils/Exception.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,28 @@
# include <system_error>

# include <boost/system/error_code.hpp>
# include <httpp/detail/config.hpp>
# include <httpp/http/client/Request.hpp>

namespace HTTPP
{
namespace UTILS
{
struct OperationAborted : public std::runtime_error

# if HTTPP_USE_BOOST_PROMISE
# define BASE_EXCEPTION public std::runtime_error, public virtual boost::exception
# else
# define BASE_EXCEPTION public std::runtime_error
# endif

struct OperationAborted : BASE_EXCEPTION
{
OperationAborted() : std::runtime_error("Operation Aborted")
{
}
};

class RequestError : public std::runtime_error
class RequestError : BASE_EXCEPTION
{
public:
RequestError(const std::string& str, HTTP::client::Request&& request)
Expand Down
10 changes: 5 additions & 5 deletions src/httpp/http/client/Connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Connection::~Connection()
{
BOOST_LOG_TRIVIAL(error)
<< "Destroy a not completed connection: " << this;
complete(std::make_exception_ptr(
complete(HTTPP::detail::make_exception_ptr(
std::runtime_error("Destroy a non completed connection")));
}
catch (const std::exception& ex)
Expand Down Expand Up @@ -115,7 +115,7 @@ void Connection::init(std::map<curl_socket_t, boost::asio::ip::tcp::socket*>& so
header.clear();
buffer.clear();

promise = std::promise<client::Response>();
promise = Promise<client::Response>();
completion_handler = CompletionHandler();
response = Response();
poll_action = 0;
Expand Down Expand Up @@ -332,7 +332,7 @@ void Connection::buildResponse(CURLcode code)
{
if (code != CURLE_OK)
{
complete(std::make_exception_ptr(RequestError(
complete(HTTPP::detail::make_exception_ptr(RequestError(
curl_easy_strerror(code) + std::string(this->error_buffer),
std::move(request))));
return;
Expand Down Expand Up @@ -377,15 +377,15 @@ void Connection::buildResponse(CURLcode code)
{
BOOST_LOG_TRIVIAL(error)
<< "Error when building the response: " << exc.what();
complete(std::make_exception_ptr(RequestNestedError(
complete(HTTPP::detail::make_exception_ptr(RequestNestedError(
"Exception happened during buildResponse " + std::string(exc.what()),
std::move(response.request))));
return;
}

}

void Connection::complete(std::exception_ptr ex)
void Connection::complete(ExceptionPtr ex)
{
bool expected = false;
if (!result_notified.compare_exchange_strong(expected, true))
Expand Down
19 changes: 13 additions & 6 deletions src/httpp/http/client/Connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
# include <boost/asio.hpp>
# include <boost/log/trivial.hpp>

# include "httpp/detail/config.hpp"
# include "httpp/utils/ThreadPool.hpp"
# include "httpp/http/Protocol.hpp"
# include "httpp/http/client/Request.hpp"
Expand All @@ -42,9 +43,15 @@ struct Connection : public std::enable_shared_from_this<Connection>
{
using ConnectionPtr = std::shared_ptr<Connection>;

// duplicate alias from HttpClient
using Future = std::future<Response>;
using CompletionHandler = std::function<void (Future&&)>;
template <typename T>
using Promise = HTTPP::detail::Promise<T>;

template <typename T>
using Future = HTTPP::detail::Future<T>;

using ExceptionPtr = HTTPP::detail::ExceptionPtr;

using CompletionHandler = std::function<void (Future<Response>&&)>;

Connection(Manager& manager, boost::asio::io_service& service);

Expand Down Expand Up @@ -94,7 +101,7 @@ struct Connection : public std::enable_shared_from_this<Connection>
void cancel();

void buildResponse(CURLcode code);
void complete(std::exception_ptr ex = nullptr);
void complete(ExceptionPtr ex = ExceptionPtr());
void setSocket(curl_socket_t socket);

template <typename Cb>
Expand All @@ -106,7 +113,7 @@ struct Connection : public std::enable_shared_from_this<Connection>
BOOST_LOG_TRIVIAL(error)
<< "Unknow poll operation requested: " << action;

complete(std::make_exception_ptr(
complete(HTTPP::detail::make_exception_ptr(
std::runtime_error("Unknow poll operation requested")));
break;
case CURL_POLL_IN:
Expand Down Expand Up @@ -145,7 +152,7 @@ struct Connection : public std::enable_shared_from_this<Connection>
client::Request request;
client::Response response;

std::promise<client::Response> promise;
Promise<client::Response> promise;
CompletionHandler completion_handler;
bool expect_continue = false;
std::vector<char> header;
Expand Down
41 changes: 21 additions & 20 deletions src/httpp/http/client/Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ Manager::Manager(UTILS::ThreadPool& io, UTILS::ThreadPool& dispatch)

Manager::~Manager()
{
std::vector<std::future<void>> futures;
std::vector<Future<void>> futures;
{
std::promise<void> promise;
Promise<void> promise;
auto future = promise.get_future();

io.dispatch([this, &promise, &futures]
Expand Down Expand Up @@ -99,7 +99,7 @@ Manager::~Manager()
}

{
std::promise<void> promise;
Promise<void> promise;
auto future = promise.get_future();
io.dispatch([this, &promise]
{
Expand Down Expand Up @@ -264,7 +264,7 @@ void Manager::checkHandles()

cancelled.first->poll_action = 0;
cancelled.first->complete(
std::make_exception_ptr(UTILS::OperationAborted()));
HTTPP::detail::make_exception_ptr(UTILS::OperationAborted()));
cancelled.second.set_value();

if (current_connections.count(cancelled.first))
Expand All @@ -291,7 +291,7 @@ void Manager::performOp(std::shared_ptr<Connection> connection,
if (ec != boost::asio::error::operation_aborted)
{
BOOST_LOG_TRIVIAL(warning) << "Error on socket: " << ec.message();
connection->complete(std::make_exception_ptr(
connection->complete(HTTPP::detail::make_exception_ptr(
std::runtime_error("Error on socket: " + ec.message())));
}

Expand All @@ -313,9 +313,10 @@ void Manager::performOp(std::shared_ptr<Connection> connection,
{
BOOST_LOG_TRIVIAL(error)
<< "Error happened in perfomOp: " << curl_multi_strerror(rc);
auto exc = std::make_exception_ptr(std::runtime_error(curl_multi_strerror(rc)));
auto exc = HTTPP::detail::make_exception_ptr(
std::runtime_error(curl_multi_strerror(rc)));
connection->complete(exc);
std::rethrow_exception(exc);
HTTPP::detail::rethrow_exception(exc);
}

checkHandles();
Expand Down Expand Up @@ -365,10 +366,9 @@ void Manager::poll(std::shared_ptr<Connection> connection, int action)
}
}


std::future<void> Manager::cancel_connection(std::shared_ptr<Connection> connection)
Manager::Future<void> Manager::cancel_connection(std::shared_ptr<Connection> connection)
{
auto promise = std::make_shared<std::promise<void>>();
auto promise = std::make_shared<Promise<void>>();
auto future = promise->get_future();

io.dispatch(std::bind(&Manager::cancel_connection_io_thread,
Expand All @@ -379,18 +379,18 @@ std::future<void> Manager::cancel_connection(std::shared_ptr<Connection> connect
}

void Manager::cancel_connection_io_thread(std::shared_ptr<Connection> connection,
std::shared_ptr<std::promise<void>> promise_ptr)
std::shared_ptr<Promise<void>> promise_ptr)
{

std::promise<void> promise = std::move(*promise_ptr);
Promise<void> promise = std::move(*promise_ptr);
promise_ptr.reset();

auto it = current_connections.find(connection);

if (it == std::end(current_connections))
{
BOOST_LOG_TRIVIAL(warning) << "Cannot cancel a completed connection";
promise.set_exception(std::make_exception_ptr(
promise.set_exception(HTTPP::detail::make_exception_ptr(
std::runtime_error("Connection already completed")));
return;
}
Expand Down Expand Up @@ -435,7 +435,7 @@ void Manager::cancelConnection(std::shared_ptr<Connection> connection)

int Manager::closeSocket(curl_socket_t curl_socket)
{
std::promise<int> promise;
Promise<int> promise;
auto future = promise.get_future();

io.dispatch([this, curl_socket, &promise]
Expand Down Expand Up @@ -478,7 +478,7 @@ void Manager::handleRequest(Method method, Connection::ConnectionPtr conn)
{
BOOST_LOG_TRIVIAL(error)
<< "Error when configuring the request: " << exc.what();
conn->complete(std::current_exception());
conn->complete(HTTPP::detail::current_exception());
return;
}

Expand All @@ -488,9 +488,10 @@ void Manager::handleRequest(Method method, Connection::ConnectionPtr conn)
{
BOOST_LOG_TRIVIAL(error)
<< "Connection already present: " << conn;
conn->complete(std::make_exception_ptr(std::runtime_error(
"Cannot schedule an operation for an already "
"managed connection")));
conn->complete(
HTTPP::detail::make_exception_ptr(std::runtime_error(
"Cannot schedule an operation for an already "
"managed connection")));
return;
}

Expand All @@ -501,8 +502,8 @@ void Manager::handleRequest(Method method, Connection::ConnectionPtr conn)
BOOST_LOG_TRIVIAL(error)
<< "Error scheduling a new request: " << message;
removeConnection(conn);
conn->complete(
std::make_exception_ptr(std::runtime_error(message)));
conn->complete(HTTPP::detail::make_exception_ptr(
std::runtime_error(message)));
return;
}

Expand Down
Loading

0 comments on commit b7d9a36

Please sign in to comment.