diff --git a/Makefile.am b/Makefile.am
index c363389a3..ed4717a2e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -343,6 +343,10 @@ include_bitcoin_network_impl_messages_rpc_HEADERS = \
include/bitcoin/network/impl/messages/rpc/broadcaster.ipp \
include/bitcoin/network/impl/messages/rpc/dispatcher.ipp
+include_bitcoin_network_impl_protocolsdir = ${includedir}/bitcoin/network/impl/protocols
+include_bitcoin_network_impl_protocols_HEADERS = \
+ include/bitcoin/network/impl/protocols/protocol_rpc.ipp
+
include_bitcoin_network_interfacesdir = ${includedir}/bitcoin/network/interfaces
include_bitcoin_network_interfaces_HEADERS = \
include/bitcoin/network/interfaces/http.hpp \
diff --git a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj
index 3d395caff..88dc1d7c2 100644
--- a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj
@@ -381,6 +381,7 @@
+
diff --git a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters
index 742e702ee..9e7c2d1f3 100644
--- a/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-network/libbitcoin-network.vcxproj.filters
@@ -35,7 +35,7 @@
{564EB540-D6B6-425C-0000-0000000000C1}
- {564EB540-D6B6-425C-0000-0000000000F1}
+ {564EB540-D6B6-425C-0000-000000000002}
{564EB540-D6B6-425C-0000-0000000000D1}
@@ -44,7 +44,10 @@
{564EB540-D6B6-425C-0000-0000000000E1}
- {564EB540-D6B6-425C-0000-000000000002}
+ {564EB540-D6B6-425C-0000-000000000003}
+
+
+ {564EB540-D6B6-425C-0000-0000000000F1}
{564EB540-D6B6-425C-0000-000000000006}
@@ -56,25 +59,25 @@
{564EB540-D6B6-425C-0000-000000000008}
- {564EB540-D6B6-425C-0000-000000000003}
+ {564EB540-D6B6-425C-0000-000000000004}
- {564EB540-D6B6-425C-0000-000000000006}
+ {564EB540-D6B6-425C-0000-000000000007}
- {564EB540-D6B6-425C-0000-000000000004}
+ {564EB540-D6B6-425C-0000-000000000005}
- {564EB540-D6B6-425C-0000-000000000007}
+ {564EB540-D6B6-425C-0000-000000000008}
- {564EB540-D6B6-425C-0000-000000000008}
+ {564EB540-D6B6-425C-0000-000000000009}
- {564EB540-D6B6-425C-0000-000000000005}
+ {564EB540-D6B6-425C-0000-000000000006}
- {564EB540-D6B6-425C-0000-000000000009}
+ {564EB540-D6B6-425C-0000-000000000010}
{564EB540-D6B6-425C-0000-000000000009}
@@ -86,7 +89,7 @@
{564EB540-D6B6-425C-0000-0000000000A1}
- {564EB540-D6B6-425C-0000-000000000010}
+ {564EB540-D6B6-425C-0000-000000000011}
{564EB540-D6B6-425C-0000-000000000000}
@@ -892,6 +895,9 @@
include\bitcoin\network\impl\messages\rpc
+
+ include\bitcoin\network\impl\protocols
+
diff --git a/include/bitcoin/network/channels/channel_rpc.hpp b/include/bitcoin/network/channels/channel_rpc.hpp
index 93509b9a2..921c8a17e 100644
--- a/include/bitcoin/network/channels/channel_rpc.hpp
+++ b/include/bitcoin/network/channels/channel_rpc.hpp
@@ -57,18 +57,20 @@ class channel_rpc
{
}
- /// Serialize and write response to client (requires strand).
- /// Completion handler is always invoked on the channel strand.
- inline void send(rpc::response_t&& message, size_t size_hint,
- result_handler&& handler) NOEXCEPT;
+ /// Public senders, rpc version and identity added to responses.
+ inline void send_code(const code& ec) NOEXCEPT;
+ inline void send_error(rpc::result_t&& error) NOEXCEPT;
+ inline void send_result(rpc::value_t&& result, size_t size_hint) NOEXCEPT;
/// Resume reading from the socket (requires strand).
inline void resume() NOEXCEPT override;
- /// Must call after successful message handling if no stop.
- virtual inline void receive() NOEXCEPT;
-
protected:
+ /// Serialize and write response to client (requires strand).
+ /// Completion handler is always invoked on the channel strand.
+ inline void send(rpc::response_t&& message, size_t size_hint,
+ result_handler&& handler) NOEXCEPT;
+
/// Stranded handler invoked from stop().
inline void stopping(const code& ec) NOEXCEPT override;
@@ -82,13 +84,21 @@ class channel_rpc
virtual inline rpc::response_ptr assign_message(rpc::response_t&& message,
size_t size_hint) NOEXCEPT;
- /// Handlers.
+ /// Must call after successful message handling if no stop.
+ virtual inline void receive() NOEXCEPT;
+
+ /// Handle incoming messages.
virtual inline void handle_receive(const code& ec, size_t bytes,
const rpc::request_cptr& request) NOEXCEPT;
+
+ /// Handle send complation, handler must invoke receive() unless stopping.
virtual inline void handle_send(const code& ec, size_t bytes,
const rpc::response_cptr& response,
const result_handler& handler) NOEXCEPT;
+ /// Invoked upon handle_send completion to restart receive().
+ virtual void handle_complete(const code& ec) NOEXCEPT;
+
private:
void log_message(const rpc::request& request,
size_t bytes) const NOEXCEPT;
@@ -96,6 +106,8 @@ class channel_rpc
size_t bytes) const NOEXCEPT;
// These are protected by strand.
+ rpc::version version_;
+ rpc::id_option identity_;
http::flat_buffer_ptr response_buffer_;
http::flat_buffer request_buffer_;
dispatcher dispatcher_{};
diff --git a/include/bitcoin/network/impl/channels/channel_rpc.ipp b/include/bitcoin/network/impl/channels/channel_rpc.ipp
index 89d9290d0..d0d807f0f 100644
--- a/include/bitcoin/network/impl/channels/channel_rpc.ipp
+++ b/include/bitcoin/network/impl/channels/channel_rpc.ipp
@@ -101,6 +101,10 @@ inline void CLASS::handle_receive(const code& ec, size_t bytes,
return;
}
+ // Save response state.
+ identity_ = request->message.id;
+ version_ = request->message.jsonrpc;
+
reading_ = false;
log_message(*request, bytes);
dispatch(request);
@@ -109,6 +113,7 @@ inline void CLASS::handle_receive(const code& ec, size_t bytes,
TEMPLATE
inline void CLASS::dispatch(const rpc::request_cptr& request) NOEXCEPT
{
+ BC_ASSERT(stranded());
if (const auto code = dispatcher_.notify(request->message))
stop(code);
}
@@ -116,22 +121,50 @@ inline void CLASS::dispatch(const rpc::request_cptr& request) NOEXCEPT
TEMPLATE
inline http::flat_buffer& CLASS::request_buffer() NOEXCEPT
{
+ BC_ASSERT(stranded());
return request_buffer_;
}
// Send.
// ----------------------------------------------------------------------------
+TEMPLATE
+void CLASS::send_code(const code& ec) NOEXCEPT
+{
+ BC_ASSERT(stranded());
+ send_error({ .code = ec.value(), .message = ec.message() });
+}
+
+TEMPLATE
+void CLASS::send_error(rpc::result_t&& error) NOEXCEPT
+{
+ BC_ASSERT(stranded());
+ using namespace std::placeholders;
+ send({ .jsonrpc = version_, .id = identity_, .error = std::move(error) },
+ two * error.message.size(), std::bind(&CLASS::handle_complete,
+ shared_from_base(), _1));
+}
+
+TEMPLATE
+void CLASS::send_result(rpc::value_t&& result, size_t size_hint) NOEXCEPT
+{
+ BC_ASSERT(stranded());
+ using namespace std::placeholders;
+ send({ .jsonrpc = version_, .id = identity_, .result = std::move(result) },
+ size_hint, std::bind(&CLASS::handle_complete,
+ shared_from_base(), _1));
+}
+
+// protected
TEMPLATE
inline void CLASS::send(rpc::response_t&& model, size_t size_hint,
result_handler&& handler) NOEXCEPT
{
BC_ASSERT(stranded());
-
using namespace std::placeholders;
const auto out = assign_message(std::move(model), size_hint);
- count_handler complete = std::bind(&channel_rpc::handle_send,
- shared_from_base(), _1, _2, out, std::move(handler));
+ count_handler complete = std::bind(&CLASS::handle_send,
+ shared_from_base(), _1, _2, out, std::move(handler));
if (!out)
{
@@ -142,22 +175,35 @@ inline void CLASS::send(rpc::response_t&& model, size_t size_hint,
write(*out, std::move(complete));
}
+// protected
TEMPLATE
inline void CLASS::handle_send(const code& ec, size_t bytes,
const rpc::response_cptr& response, const result_handler& handler) NOEXCEPT
{
- if (ec)
- stop(ec);
-
+ BC_ASSERT(stranded());
+ if (ec) stop(ec);
log_message(*response, bytes);
handler(ec);
}
+// protected
+TEMPLATE
+void CLASS::handle_complete(const code&) NOEXCEPT
+{
+ BC_ASSERT(stranded());
+ if (stopped())
+ return;
+
+ // Continue read loop.
+ receive();
+}
+
// private
TEMPLATE
inline rpc::response_ptr CLASS::assign_message(rpc::response_t&& message,
size_t size_hint) NOEXCEPT
{
+ BC_ASSERT(stranded());
response_buffer_->max_size(size_hint);
const auto ptr = system::to_shared();
ptr->message = std::move(message);
diff --git a/include/bitcoin/network/impl/protocols/protocol_rpc.ipp b/include/bitcoin/network/impl/protocols/protocol_rpc.ipp
new file mode 100644
index 000000000..7d92f2b21
--- /dev/null
+++ b/include/bitcoin/network/impl/protocols/protocol_rpc.ipp
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
+ *
+ * This file is part of libbitcoin.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+#ifndef LIBBITCOIN_NETWORK_PROTOCOL_RPC_IPP
+#define LIBBITCOIN_NETWORK_PROTOCOL_RPC_IPP
+
+#include
+#include
+
+namespace libbitcoin {
+namespace network {
+
+TEMPLATE
+inline void CLASS::send_code(const code& ec) NOEXCEPT
+{
+ channel_->send_code(ec);
+}
+
+TEMPLATE
+inline void CLASS::send_error(rpc::result_t&& error) NOEXCEPT
+{
+ channel_->send_error(std::move(error));
+}
+
+TEMPLATE
+inline void CLASS::send_result(rpc::value_t&& result,
+ size_t size_hint) NOEXCEPT
+{
+ channel_->send_result(std::move(result), size_hint);
+}
+
+} // namespace network
+} // namespace libbitcoin
+
+#endif
diff --git a/include/bitcoin/network/protocols/protocol_rpc.hpp b/include/bitcoin/network/protocols/protocol_rpc.hpp
index 8d0ee94d3..b9e9a7778 100644
--- a/include/bitcoin/network/protocols/protocol_rpc.hpp
+++ b/include/bitcoin/network/protocols/protocol_rpc.hpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
namespace libbitcoin {
@@ -33,8 +34,7 @@ class protocol_rpc
: public protocol
{
public:
- typedef std::shared_ptr ptr;
- using protocol_t = protocol_rpc;
+ typedef std::shared_ptr> ptr;
using channel_t = channel_rpc;
using options_t = channel_t::options_t;
@@ -48,67 +48,11 @@ class protocol_rpc
DECLARE_SUBSCRIBE_CHANNEL()
- template
- inline void send(network::rpc::response_t&& message, size_t size_hint,
- Method&& method, Args&&... args) NOEXCEPT
- {
- channel_->send(std::move(message), size_hint,
- std::bind(std::forward(method),
- shared_from_base(), std::forward(args)...));
- }
-
- // TODO: capture and correlate version/id.
- inline void send_result(network::rpc::value_t&& value,
- size_t size_hint) NOEXCEPT
- {
- using namespace network::rpc;
- using namespace std::placeholders;
- send(
- {
- .jsonrpc = version::v2,
- .id = 42,
- ////.error = {},
- .result = std::move(value)
- },
- size_hint, &protocol_t::handle_complete, _1, error::success);
- }
-
- // TODO: capture and correlate version/id.
- inline void send_error(const code& reason) NOEXCEPT
- {
- using namespace network::rpc;
- using namespace std::placeholders;
- const auto size_hint = two * reason.message().size();
- send(
- {
- .jsonrpc = version::v2,
- .id = 42,
- .error = result_t
- {
- .code = reason.value(),
- .message = reason.message()
- }
- ////.result = {}
- },
- size_hint, &protocol_t::handle_complete, _1, reason);
- }
-
- inline void handle_complete(const code& ec, const code& reason) NOEXCEPT
- {
- BC_ASSERT(stranded());
-
- if (stopped(ec))
- return;
-
- if (reason)
- {
- stop(reason);
- return;
- }
-
- // Continue read loop.
- channel_->receive();
- }
+ /// Senders (requires strand).
+ virtual inline void send_code(const code& ec) NOEXCEPT;
+ virtual inline void send_error(rpc::result_t&& error) NOEXCEPT;
+ virtual inline void send_result(rpc::value_t&& result,
+ size_t size_hint) NOEXCEPT;
private:
// This is mostly thread safe, and used in a thread safe manner.
@@ -119,4 +63,12 @@ class protocol_rpc
} // namespace network
} // namespace libbitcoin
+#define TEMPLATE template
+#define CLASS protocol_rpc
+
+#include
+
+#undef CLASS
+#undef TEMPLATE
+
#endif