View in context in the libbitcoin Slack #general mirror.
///////////////////////////////////////////////////////////////////////////////
// This is all just boilerplate...
///////////////////////////////////////////////////////////////////////////////
// Proxy... these just hide the socket from channels.
// Reads.
// ----------------------------------------------------------------------------
void proxy::read(http_flat_buffer& buffer, http_string_request& request,
count_handler&& handler) NOEXCEPT
{
socket_->http_read(buffer, request, std::move(handler));
}
// Writes.
// ----------------------------------------------------------------------------
// Writes are composed but http is half duplex so there is no interleave risk.
void proxy::write(const http_string_response& response,
count_handler&& handler) NOEXCEPT
{
socket_->http_write(response, std::move(handler));
}
void proxy::write(const http_data_response& response,
count_handler&& handler) NOEXCEPT
{
socket_->http_write(response, std::move(handler));
}
void proxy::write(http_file_response& response,
count_handler&& handler) NOEXCEPT
{
socket_->http_write(response, std::move(handler));
}
// Socket... these just ensure that socket calls are stranded (thread safe).
// There is no actual post to the strand if the caller is already stranded.
// HTTP I/O.
// ----------------------------------------------------------------------------
void socket::http_read(http_flat_buffer& buffer, http_string_request& request,
count_handler&& handler) NOEXCEPT
{
boost::asio::dispatch(strand_,
std::bind(&socket::do_http_read_string_buffered, shared_from_this(),
std::ref(buffer), std::ref(request), std::move(handler)));
}
void socket::http_write(const http_string_response& response,
count_handler&& handler) NOEXCEPT
{
boost::asio::dispatch(strand_,
std::bind(&socket::do_http_write_string,
shared_from_this(), std::cref(response), std::move(handler)));
}
void socket::http_write(const http_data_response& response,
count_handler&& handler) NOEXCEPT
{
boost::asio::dispatch(strand_,
std::bind(&socket::do_http_write_data,
shared_from_this(), std::cref(response), std::move(handler)));
}
void socket::http_write(http_file_response& response,
count_handler&& handler) NOEXCEPT
{
boost::asio::dispatch(strand_,
std::bind(&socket::do_http_write_file,
shared_from_this(), std::ref(response), std::move(handler)));
}
// Socket... these ensure that socket calls are exception safe (and manage read buffer consumption).
// http executors (private).
// ----------------------------------------------------------------------------
void socket::do_http_read_string_buffered(
const std::reference_wrapper<http_flat_buffer>& buffer,
const std::reference_wrapper<http_string_request>& request,
const count_handler& handler) NOEXCEPT
{
BC_ASSERT_MSG(stranded(), "strand");
auto complete = [=](const code& ec, size_t size) NOEXCEPT
{
buffer.get().consume(size);
handler(ec, size);
};
try
{
// This operation posts handler to the strand.
boost::beast::http::async_read(socket_, buffer.get(), request.get(),
std::bind(&socket::handle_http,
shared_from_this(), _1, _2, std::move(complete)));
}
catch (const std::exception& LOG_ONLY(e))
{
LOGF("Exception @ do_http_read_string_buffered: " << e.what());
handler(error::operation_failed, zero);
}
}
void socket::do_http_write_string(
const std::reference_wrapper<const http_string_response>& response,
const count_handler& handler) NOEXCEPT
{
BC_ASSERT_MSG(stranded(), "strand");
try
{
// This operation posts handler to the strand.
boost::beast::http::async_write(socket_, response.get(),
std::bind(&socket::handle_http,
shared_from_this(), _1, _2, handler));
}
catch (const std::exception& LOG_ONLY(e))
{
LOGF("Exception @ do_http_write_string: " << e.what());
handler(error::operation_failed, zero);
}
}
void socket::do_http_write_data(
const std::reference_wrapper<const http_data_response>& response,
const count_handler& handler) NOEXCEPT
{
BC_ASSERT_MSG(stranded(), "strand");
try
{
// This operation posts handler to the strand.
boost::beast::http::async_write(socket_, response.get(),
std::bind(&socket::handle_http,
shared_from_this(), _1, _2, handler));
}
catch (const std::exception& LOG_ONLY(e))
{
LOGF("Exception @ do_http_write_data: " << e.what());
handler(error::operation_failed, zero);
}
}
void socket::do_http_write_file(
const std::reference_wrapper<http_file_response>& response,
const count_handler& handler) NOEXCEPT
{
BC_ASSERT_MSG(stranded(), "strand");
const auto writer = std::make_shared<http_file_serializer>(response.get());
auto complete = [writer, handler](const code& ec, size_t size) NOEXCEPT
{
handler(ec, size);
};
try
{
// This operation posts handler to the strand.
boost::beast::http::async_write(socket_, *writer,
std::bind(&socket::handle_http,
shared_from_this(), _1, _2, std::move(complete)));
}
catch (const std::exception& LOG_ONLY(e))
{
LOGF("Exception @ do_http_write_file: " << e.what());
handler(error::operation_failed, zero);
}
}
// Socket... this just normalizes to our return codes (from boost codes).
// handlers (private).
// ----------------------------------------------------------------------------
void socket::handle_http(const error::boost_code& ec, size_t size,
const count_handler& handler) NOEXCEPT
{
BC_ASSERT_MSG(stranded(), "strand");
if (error::asio_is_canceled(ec))
{
handler(error::channel_stopped, size);
return;
}
// Translate other beast error codes and invoke caller handler.
handler(error::beast_to_error_code(ec), size);
} (edited)