Jonathan "Duke" Leto
4 years ago
40 changed files with 113 additions and 1602 deletions
@ -1,48 +0,0 @@ |
|||
#!/usr/bin/env python2 |
|||
# Copyright (c) 2017 The Zcash developers |
|||
# Distributed under the MIT software license, see the accompanying |
|||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
|||
|
|||
# Requirements: |
|||
# pip install python-qpid-proton |
|||
|
|||
import binascii |
|||
from proton.handlers import MessagingHandler |
|||
from proton.reactor import Container |
|||
|
|||
port = 5672 |
|||
|
|||
class Server(MessagingHandler): |
|||
def __init__(self, url): |
|||
super(Server, self).__init__() |
|||
self.url = url |
|||
self.senders = {} |
|||
|
|||
def on_start(self, event): |
|||
print "Listening on:", self.url |
|||
self.container = event.container |
|||
self.acceptor = event.container.listen(self.url) |
|||
|
|||
def on_message(self, event): |
|||
m = event.message |
|||
topic = m.subject |
|||
body = m.body |
|||
sequence = str( m.properties['x-opt-sequence-number'] ) |
|||
if topic == "hashablock": |
|||
print '- HASH BLOCK ('+sequence+') -' |
|||
print binascii.hexlify(body) |
|||
elif topic == "hashtx": |
|||
print '- HASH TX ('+sequence+') -' |
|||
print binascii.hexlify(body) |
|||
elif topic == "rawblock": |
|||
print '- RAW BLOCK HEADER ('+sequence+') -' |
|||
print binascii.hexlify(body[:80]) |
|||
elif topic == "rawtx": |
|||
print '- RAW TX ('+sequence+') -' |
|||
print binascii.hexlify(body) |
|||
|
|||
try: |
|||
Container(Server("127.0.0.1:%i" % port)).run() |
|||
except KeyboardInterrupt: |
|||
pass |
|||
|
@ -1,23 +0,0 @@ |
|||
package=proton |
|||
$(package)_version=0.26.0 |
|||
$(package)_download_path=https://archive.apache.org/dist/qpid/proton/$($(package)_version) |
|||
$(package)_file_name=qpid-proton-$($(package)_version).tar.gz |
|||
$(package)_sha256_hash=0eddac870f0085b9aeb0c9da333bd3f53fedb7c872164171a7cc06761ddbbd75 |
|||
$(package)_patches=minimal-build.patch |
|||
|
|||
define $(package)_preprocess_cmds |
|||
patch -p1 < $($(package)_patch_dir)/minimal-build.patch && \
|
|||
mkdir -p build/proton-c/src |
|||
endef |
|||
|
|||
define $(package)_config_cmds |
|||
cd build; cmake .. -DCMAKE_CXX_STANDARD=11 -DCMAKE_INSTALL_PREFIX=/ -DSYSINSTALL_BINDINGS=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_PYTHON=OFF -DBUILD_PHP=OFF -DBUILD_JAVA=OFF -DBUILD_PERL=OFF -DBUILD_RUBY=OFF -DBUILD_JAVASCRIPT=OFF -DBUILD_GO=OFF -DBUILD_STATIC_LIBS=ON |
|||
endef |
|||
|
|||
define $(package)_build_cmds |
|||
cd build; $(MAKE) VERBOSE=1 |
|||
endef |
|||
|
|||
define $(package)_stage_cmds |
|||
cd build; $(MAKE) VERBOSE=1 DESTDIR=$($(package)_staging_prefix_dir) install |
|||
endef |
@ -1,288 +0,0 @@ |
|||
From 03f5fc0826115edbfca468261b70c0daf627f488 Mon Sep 17 00:00:00 2001 |
|||
From: Simon <simon@bitcartel.com> |
|||
Date: Thu, 27 Apr 2017 17:15:59 -0700 |
|||
Subject: [PATCH] Enable C++11, build static library and cpp bindings with minimal dependencies. |
|||
|
|||
---
|
|||
CMakeLists.txt | 13 +++++++------ |
|||
examples/cpp/CMakeLists.txt | 1 + |
|||
proton-c/CMakeLists.txt | 32 +++++++++++++++---------------- |
|||
proton-c/bindings/CMakeLists.txt | 6 +++--- |
|||
proton-c/bindings/cpp/CMakeLists.txt | 24 +++++++++++------------ |
|||
proton-c/bindings/cpp/docs/CMakeLists.txt | 2 +- |
|||
proton-c/docs/api/CMakeLists.txt | 2 +- |
|||
7 files changed, 41 insertions(+), 39 deletions(-) |
|||
|
|||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|||
index b538ffd..4a5e787 100644
|
|||
--- a/CMakeLists.txt
|
|||
+++ b/CMakeLists.txt
|
|||
@@ -18,14 +18,15 @@
|
|||
# |
|||
cmake_minimum_required (VERSION 2.8.7) |
|||
|
|||
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
|||
project (Proton C) |
|||
|
|||
# Enable C++ now for examples and bindings subdirectories, but make it optional. |
|||
enable_language(CXX OPTIONAL) |
|||
|
|||
# Enable testing |
|||
-enable_testing()
|
|||
-include (CTest)
|
|||
+#enable_testing()
|
|||
+#include (CTest)
|
|||
|
|||
# Pull in local cmake modules |
|||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/tools/cmake/Modules/") |
|||
@@ -141,7 +142,7 @@ set (BINDINGS_DIR ${LIB_INSTALL_DIR}/proton/bindings)
|
|||
|
|||
set (SYSINSTALL_BINDINGS OFF CACHE BOOL "If SYSINSTALL_BINDINGS is OFF then proton bindings will be installed underneath ${BINDINGS_DIR} and each user will need to modify their interpreter configuration to load the appropriate binding. If SYSINSTALL_BINDINGS is ON, then each language interpreter will be queried for the appropriate directory and proton bindings will be installed and available system wide with no additional per user configuration.") |
|||
|
|||
-set (BINDING_LANGS PERL PHP PYTHON RUBY)
|
|||
+#set (BINDING_LANGS PERL PHP PYTHON RUBY)
|
|||
|
|||
foreach (LANG ${BINDING_LANGS}) |
|||
set (SYSINSTALL_${LANG} OFF CACHE BOOL "Install ${LANG} bindings into interpreter specified location.") |
|||
@@ -156,10 +157,10 @@ set (PROTON_SHARE ${SHARE_INSTALL_DIR}/proton-${PN_VERSION})
|
|||
# End of variables used during install |
|||
|
|||
# Check for valgrind here so tests under proton-c/ and examples/ can use it. |
|||
-find_program(VALGRIND_EXE valgrind DOC "Location of the valgrind program")
|
|||
+#find_program(VALGRIND_EXE valgrind DOC "Location of the valgrind program")
|
|||
mark_as_advanced (VALGRIND_EXE) |
|||
|
|||
-option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON)
|
|||
+#option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON)
|
|||
if (ENABLE_VALGRIND) |
|||
if (NOT VALGRIND_EXE) |
|||
message(STATUS "Can't locate the valgrind command; no run-time error detection") |
|||
@@ -171,7 +172,7 @@ if (ENABLE_VALGRIND)
|
|||
endif (ENABLE_VALGRIND) |
|||
|
|||
add_subdirectory(proton-c) |
|||
-add_subdirectory(examples)
|
|||
+#add_subdirectory(examples)
|
|||
|
|||
install (FILES LICENSE README.md |
|||
DESTINATION ${PROTON_SHARE}) |
|||
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
|
|||
index 304d899..f4877b4 100644
|
|||
--- a/examples/cpp/CMakeLists.txt
|
|||
+++ b/examples/cpp/CMakeLists.txt
|
|||
@@ -17,6 +17,7 @@
|
|||
# under the License. |
|||
# |
|||
|
|||
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
|||
find_package(ProtonCpp REQUIRED) |
|||
|
|||
include_directories(${ProtonCpp_INCLUDE_DIRS}) |
|||
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
|
|||
index 8edb661..dc7b99c 100644
|
|||
--- a/proton-c/CMakeLists.txt
|
|||
+++ b/proton-c/CMakeLists.txt
|
|||
@@ -22,24 +22,24 @@ include(CheckSymbolExists)
|
|||
|
|||
include(soversion.cmake) |
|||
|
|||
-add_custom_target(docs)
|
|||
-add_custom_target(doc DEPENDS docs)
|
|||
+#add_custom_target(docs)
|
|||
+#add_custom_target(doc DEPENDS docs)
|
|||
|
|||
# Set the default SSL/TLS implementation |
|||
-find_package(OpenSSL)
|
|||
+#find_package(OpenSSL)
|
|||
find_package(PythonInterp REQUIRED) |
|||
-find_package(SWIG)
|
|||
+#find_package(SWIG)
|
|||
# FindSwig.cmake "forgets" make its outputs advanced like a good citizen |
|||
mark_as_advanced(SWIG_DIR SWIG_EXECUTABLE SWIG_VERSION) |
|||
|
|||
# See if Cyrus SASL is available |
|||
-find_library(CYRUS_SASL_LIBRARY sasl2)
|
|||
-find_path(CYRUS_SASL_INCLUDE_DIR sasl/sasl.h PATH_SUFFIXES include)
|
|||
-find_package_handle_standard_args(CyrusSASL DEFAULT_MSG CYRUS_SASL_LIBRARY CYRUS_SASL_INCLUDE_DIR)
|
|||
+#find_library(CYRUS_SASL_LIBRARY sasl2)
|
|||
+#find_path(CYRUS_SASL_INCLUDE_DIR sasl/sasl.h PATH_SUFFIXES include)
|
|||
+#find_package_handle_standard_args(CyrusSASL DEFAULT_MSG CYRUS_SASL_LIBRARY CYRUS_SASL_INCLUDE_DIR)
|
|||
mark_as_advanced(CYRUS_SASL_LIBRARY CYRUS_SASL_INCLUDE_DIR) |
|||
|
|||
# Find saslpasswd2 executable to generate test config |
|||
-find_program(SASLPASSWD_EXE saslpasswd2 DOC "Program used to make SASL user db for testing")
|
|||
+#find_program(SASLPASSWD_EXE saslpasswd2 DOC "Program used to make SASL user db for testing")
|
|||
mark_as_advanced(SASLPASSWD_EXE) |
|||
|
|||
if(WIN32 AND NOT CYGWIN) |
|||
@@ -315,8 +315,8 @@ pn_absolute_install_dir(EXEC_PREFIX "." ${CMAKE_INSTALL_PREFIX})
|
|||
pn_absolute_install_dir(LIBDIR ${LIB_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX}) |
|||
pn_absolute_install_dir(INCLUDEDIR ${INCLUDE_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX}) |
|||
|
|||
-add_subdirectory(docs/api)
|
|||
-add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
|
|||
+#add_subdirectory(docs/api)
|
|||
+#add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c)
|
|||
|
|||
# for full source distribution: |
|||
set (qpid-proton-platform-all |
|||
@@ -507,7 +507,7 @@ if (BUILD_WITH_CXX)
|
|||
endif (BUILD_WITH_CXX) |
|||
|
|||
add_library ( |
|||
- qpid-proton-core SHARED
|
|||
+ qpid-proton-core STATIC
|
|||
${qpid-proton-core} |
|||
${qpid-proton-layers} |
|||
${qpid-proton-platform} |
|||
@@ -527,7 +527,7 @@ set_target_properties (
|
|||
) |
|||
|
|||
add_library( |
|||
- qpid-proton SHARED
|
|||
+ qpid-proton STATIC
|
|||
# Proton Core |
|||
${qpid-proton-core} |
|||
${qpid-proton-layers} |
|||
@@ -629,7 +629,7 @@ install (FILES
|
|||
|
|||
# c tests: |
|||
|
|||
-add_subdirectory(src/tests)
|
|||
+#add_subdirectory(src/tests)
|
|||
|
|||
if (CMAKE_SYSTEM_NAME STREQUAL Windows) |
|||
# No change needed for windows already use correct separator |
|||
@@ -712,7 +712,7 @@ if (BUILD_PYTHON)
|
|||
|
|||
endif (BUILD_PYTHON) |
|||
|
|||
-find_program(RUBY_EXE "ruby")
|
|||
+#find_program(RUBY_EXE "ruby")
|
|||
if (RUBY_EXE AND BUILD_RUBY) |
|||
set (rb_root "${pn_test_root}/ruby") |
|||
set (rb_src "${CMAKE_CURRENT_SOURCE_DIR}/bindings/ruby") |
|||
@@ -751,8 +751,8 @@ if (RUBY_EXE AND BUILD_RUBY)
|
|||
else (DEFAULT_RUBY_TESTING) |
|||
message(STATUS "Skipping Ruby tests: missing dependencies") |
|||
endif (DEFAULT_RUBY_TESTING) |
|||
-else (RUBY_EXE)
|
|||
- message (STATUS "Cannot find ruby, skipping ruby tests")
|
|||
+#else (RUBY_EXE)
|
|||
+# message (STATUS "Cannot find ruby, skipping ruby tests")
|
|||
endif() |
|||
|
|||
mark_as_advanced (RUBY_EXE RSPEC_EXE) |
|||
diff --git a/proton-c/bindings/CMakeLists.txt b/proton-c/bindings/CMakeLists.txt
|
|||
index 6b88384..d1a50a5 100644
|
|||
--- a/proton-c/bindings/CMakeLists.txt
|
|||
+++ b/proton-c/bindings/CMakeLists.txt
|
|||
@@ -19,14 +19,14 @@
|
|||
|
|||
# Add bindings that do not require swig here - the directory name must be the same as the binding name |
|||
# See below for swig bindings |
|||
-set(BINDINGS javascript cpp go)
|
|||
+set(BINDINGS cpp)
|
|||
|
|||
# Prerequisites for javascript. |
|||
# |
|||
# It uses a C/C++ to JavaScript cross-compiler called emscripten (https://github.com/kripken/emscripten). Emscripten takes C/C++ |
|||
# and compiles it into a highly optimisable subset of JavaScript called asm.js (http://asmjs.org/) that can be |
|||
# aggressively optimised and run at near-native speed (usually between 1.5 to 10 times slower than native C/C++). |
|||
-find_package(Emscripten)
|
|||
+#find_package(Emscripten)
|
|||
if (EMSCRIPTEN_FOUND) |
|||
set (DEFAULT_JAVASCRIPT ON) |
|||
endif (EMSCRIPTEN_FOUND) |
|||
@@ -37,7 +37,7 @@ if (CMAKE_CXX_COMPILER)
|
|||
endif (CMAKE_CXX_COMPILER) |
|||
|
|||
# Prerequisites for Go |
|||
-find_program(GO_EXE go)
|
|||
+#find_program(GO_EXE go)
|
|||
mark_as_advanced(GO_EXE) |
|||
if (GO_EXE) |
|||
if(WIN32) |
|||
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
|
|||
index 0cc4024..796fe29 100644
|
|||
--- a/proton-c/bindings/cpp/CMakeLists.txt
|
|||
+++ b/proton-c/bindings/cpp/CMakeLists.txt
|
|||
@@ -16,7 +16,7 @@
|
|||
# specific language governing permissions and limitations |
|||
# under the License. |
|||
# |
|||
-
|
|||
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
|||
include(cpp.cmake) # Compiler checks |
|||
|
|||
include_directories( |
|||
@@ -89,7 +89,7 @@ set_source_files_properties (
|
|||
COMPILE_FLAGS "${LTO}" |
|||
) |
|||
|
|||
-add_library(qpid-proton-cpp SHARED ${qpid-proton-cpp-source})
|
|||
+add_library(qpid-proton-cpp STATIC ${qpid-proton-cpp-source})
|
|||
|
|||
target_link_libraries (qpid-proton-cpp ${PLATFORM_LIBS} qpid-proton) |
|||
|
|||
@@ -120,8 +120,8 @@ endif (MSVC)
|
|||
|
|||
install (DIRECTORY "include/proton" DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.hpp") |
|||
|
|||
-add_subdirectory(docs)
|
|||
-add_subdirectory(${CMAKE_SOURCE_DIR}/tests/tools/apps/cpp ${CMAKE_BINARY_DIR}/tests/tools/apps/cpp)
|
|||
+#add_subdirectory(docs)
|
|||
+#add_subdirectory(${CMAKE_SOURCE_DIR}/tests/tools/apps/cpp ${CMAKE_BINARY_DIR}/tests/tools/apps/cpp)
|
|||
|
|||
# Pkg config file |
|||
configure_file( |
|||
@@ -171,12 +171,12 @@ macro(add_cpp_test test)
|
|||
endif () |
|||
endmacro(add_cpp_test) |
|||
|
|||
-add_cpp_test(codec_test)
|
|||
+#add_cpp_test(codec_test)
|
|||
#add_cpp_test(engine_test) |
|||
-add_cpp_test(thread_safe_test)
|
|||
-add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests)
|
|||
-add_cpp_test(message_test)
|
|||
-add_cpp_test(scalar_test)
|
|||
-add_cpp_test(value_test)
|
|||
-add_cpp_test(container_test)
|
|||
-add_cpp_test(url_test)
|
|||
+#add_cpp_test(thread_safe_test)
|
|||
+#add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests)
|
|||
+#add_cpp_test(message_test)
|
|||
+#add_cpp_test(scalar_test)
|
|||
+#add_cpp_test(value_test)
|
|||
+#add_cpp_test(container_test)
|
|||
+#add_cpp_test(url_test)
|
|||
diff --git a/proton-c/bindings/cpp/docs/CMakeLists.txt b/proton-c/bindings/cpp/docs/CMakeLists.txt
|
|||
index d512d15..8576867 100644
|
|||
--- a/proton-c/bindings/cpp/docs/CMakeLists.txt
|
|||
+++ b/proton-c/bindings/cpp/docs/CMakeLists.txt
|
|||
@@ -17,7 +17,7 @@
|
|||
# under the License. |
|||
# |
|||
|
|||
-find_package(Doxygen)
|
|||
+#find_package(Doxygen)
|
|||
|
|||
if (DOXYGEN_FOUND) |
|||
configure_file ( |
|||
diff --git a/proton-c/docs/api/CMakeLists.txt b/proton-c/docs/api/CMakeLists.txt
|
|||
index 7756e48..71ebb93 100644
|
|||
--- a/proton-c/docs/api/CMakeLists.txt
|
|||
+++ b/proton-c/docs/api/CMakeLists.txt
|
|||
@@ -17,7 +17,7 @@
|
|||
# under the License. |
|||
# |
|||
|
|||
-find_package(Doxygen)
|
|||
+#find_package(Doxygen)
|
|||
if (DOXYGEN_FOUND) |
|||
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/user.doxygen.in |
|||
${CMAKE_CURRENT_BINARY_DIR}/user.doxygen) |
|||
--
|
|||
2.7.4 |
|||
|
@ -1,123 +0,0 @@ |
|||
# Block and Transaction Broadcasting With AMQP 1.0 (Experimental Feature) |
|||
|
|||
[AMQP](https://www.amqp.org/) is an enterprise-level message queuing |
|||
protocol for the reliable passing of real-time data and business |
|||
transactions between applications. AMQP supports both broker and |
|||
brokerless messaging. AMQP 1.0 is an open standard and has been |
|||
ratified as ISO/IEC 19464. |
|||
|
|||
The Hush daemon can be configured to act as a trusted "border |
|||
router", implementing the Hush P2P protocol and relay, making |
|||
consensus decisions, maintaining the local blockchain database, |
|||
broadcasting locally generated transactions into the network, and |
|||
providing a queryable RPC interface to interact on a polled basis for |
|||
requesting blockchain related data. However, there exists only a |
|||
limited service to notify external software of events like the arrival |
|||
of new blocks or transactions. |
|||
|
|||
The AMQP facility implements a notification interface through a set |
|||
of specific notifiers. Currently there are notifiers that publish |
|||
blocks and transactions. This read-only facility requires only the |
|||
connection of a corresponding AMQP subscriber port in receiving |
|||
software. |
|||
|
|||
Currently the facility is not authenticated nor is there any two-way |
|||
protocol involvement. Therefore, subscribers should validate the |
|||
received data since it may be out of date, incomplete or even invalid. |
|||
|
|||
Because AMQP is message oriented, subscribers receive transactions |
|||
and blocks all-at-once and do not need to implement any sort of |
|||
buffering or reassembly. |
|||
|
|||
## Prerequisites |
|||
|
|||
The AMQP feature in Hush requires [Qpid Proton](https://qpid.apache.org/proton/) |
|||
version 0.17 or newer, which you will need to install if you are not |
|||
using the depends system. Typically, it is packaged by distributions as |
|||
something like *libqpid-proton*. The C++ wrapper for AMQP *is* required. |
|||
|
|||
In order to run the example Python client scripts in contrib/ one must |
|||
also install *python-qpid-proton*, though this is not necessary for |
|||
daemon operation. |
|||
|
|||
## Enabling |
|||
|
|||
By default, the AMQP feature is automatically compiled in if the |
|||
necessary prerequisites are found. To disable, use --disable-proton |
|||
during the *configure* step of building zcashd: |
|||
|
|||
$ ./configure --disable-proton (other options) |
|||
|
|||
To actually enable operation, one must set the appropriate options on |
|||
the commandline or in the configuration file. |
|||
|
|||
## Usage |
|||
|
|||
AMQP support is currently an experimental feature, so you must pass |
|||
the option: |
|||
|
|||
-experimentalfeatures |
|||
|
|||
Currently, the following notifications are supported: |
|||
|
|||
-amqppubhashtx=address |
|||
-amqppubhashblock=address |
|||
-amqppubrawblock=address |
|||
-amqppubrawtx=address |
|||
|
|||
The address must be a valid AMQP address, where the same address can be |
|||
used in more than notification. Note that SSL and SASL addresses are |
|||
not currently supported. |
|||
|
|||
Launch zcashd like this: |
|||
|
|||
$ zcashd -amqppubhashtx=amqp://127.0.0.1:5672 |
|||
|
|||
Or this: |
|||
|
|||
$ zcashd -amqppubhashtx=amqp://127.0.0.1:5672 \ |
|||
-amqppubrawtx=amqp://127.0.0.1:5672 \ |
|||
-amqppubrawblock=amqp://127.0.0.1:5672 \ |
|||
-amqppubhashblock=amqp://127.0.0.1:5672 \ |
|||
-debug=amqp |
|||
|
|||
The debug category `amqp` enables AMQP-related logging. |
|||
|
|||
Each notification has a topic and body, where the header corresponds |
|||
to the notification type. For instance, for the notification `-amqpubhashtx` |
|||
the topic is `hashtx` (no null terminator) and the body is the hexadecimal |
|||
transaction hash (32 bytes). This transaction hash and the block hash |
|||
found in `hashblock` are in RPC byte order. |
|||
|
|||
These options can also be provided in zcash.conf. |
|||
|
|||
Please see `contrib/amqp/amqp_sub.py` for a working example of an |
|||
AMQP server listening for messages. |
|||
|
|||
## Remarks |
|||
|
|||
From the perspective of zcashd, the local end of an AMQP link is write-only. |
|||
|
|||
No information is broadcast that wasn't already received from the public |
|||
P2P network. |
|||
|
|||
No authentication or authorization is done on peers that zcashd connects |
|||
to; it is assumed that the AMQP link is exposed only to trusted entities, |
|||
using other means such as firewalling. |
|||
|
|||
TLS support may be added once OpenSSL has been removed from the Hush |
|||
project and alternative TLS implementations have been evaluated. |
|||
|
|||
SASL support may be added in a future update for secure communication. |
|||
|
|||
Note that when the block chain tip changes, a reorganisation may occur |
|||
and just the tip will be notified. It is up to the subscriber to |
|||
retrieve the chain from the last known block to the new tip. |
|||
|
|||
At present, zcashd does not try to resend a notification if there was |
|||
a problem confirming receipt. Support for delivery guarantees such as |
|||
*at-least-once* and *exactly-once* will be added in in a future update. |
|||
|
|||
Currently, zcashd appends an up-counting sequence number to each notification |
|||
which allows listeners to detect lost notifications. |
|||
|
@ -1,117 +0,0 @@ |
|||
#!/usr/bin/env python2 |
|||
# Copyright (c) 2017 The Zcash developers |
|||
# Distributed under the MIT software license, see the accompanying |
|||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
|||
|
|||
# |
|||
# Test Proton interface (provides AMQP 1.0 messaging support). |
|||
# |
|||
# Requirements: |
|||
# Python library for Qpid Proton: |
|||
# https://pypi.python.org/pypi/python-qpid-proton |
|||
# To install: |
|||
# pip install python-qpid-proton |
|||
# |
|||
|
|||
from test_framework.test_framework import BitcoinTestFramework |
|||
from test_framework.util import assert_equal, bytes_to_hex_str, \ |
|||
start_nodes |
|||
|
|||
from proton.handlers import MessagingHandler |
|||
from proton.reactor import Container |
|||
|
|||
import threading |
|||
|
|||
|
|||
class Server(MessagingHandler): |
|||
|
|||
def __init__(self, url, limit): |
|||
super(Server, self).__init__() |
|||
self.url = url |
|||
self.counter = limit |
|||
self.blockhashes = [] |
|||
self.txids = [] |
|||
self.blockseq = -1 |
|||
self.txidseq = -1 |
|||
|
|||
def on_start(self, event): |
|||
print "Proton listening on:", self.url |
|||
self.container = event.container |
|||
self.acceptor = event.container.listen(self.url) |
|||
|
|||
def on_message(self, event): |
|||
m = event.message |
|||
hash = bytes_to_hex_str(m.body) |
|||
sequence = m.properties['x-opt-sequence-number'] |
|||
if m.subject == "hashtx": |
|||
self.txids.append(hash) |
|||
|
|||
# Test that sequence id is incrementing |
|||
assert(sequence == 1 + self.txidseq) |
|||
self.txidseq = sequence |
|||
elif m.subject == "hashblock": |
|||
self.blockhashes.append(hash) |
|||
|
|||
# Test that sequence id is incrementing |
|||
assert(sequence == 1 + self.blockseq) |
|||
self.blockseq = sequence |
|||
|
|||
self.counter = self.counter - 1 |
|||
if self.counter == 0: |
|||
self.container.stop() |
|||
|
|||
|
|||
class ProtonTest (BitcoinTestFramework): |
|||
|
|||
port = 25672 |
|||
numblocks = 10 # must be even, as two nodes generate equal number |
|||
assert(numblocks % 2 == 0) |
|||
|
|||
def setup_nodes(self): |
|||
|
|||
# Launch proton server in background thread |
|||
# It terminates after receiving numblocks * 2 messages (one for coinbase, one for block) |
|||
self.server = Server("127.0.0.1:%i" % self.port, self.numblocks * 2) |
|||
self.container = Container(self.server) |
|||
self.t1 = threading.Thread(target=self.container.run) |
|||
self.t1.start() |
|||
|
|||
return start_nodes(4, self.options.tmpdir, extra_args=[ |
|||
['-experimentalfeatures', '-debug=amqp', '-amqppubhashtx=amqp://127.0.0.1:'+str(self.port), |
|||
'-amqppubhashblock=amqp://127.0.0.1:'+str(self.port)], |
|||
[], |
|||
[], |
|||
[] |
|||
]) |
|||
|
|||
def run_test(self): |
|||
self.sync_all() |
|||
baseheight = self.nodes[0].getblockcount() # 200 blocks already mined |
|||
|
|||
# generate some blocks |
|||
self.nodes[0].generate(self.numblocks/2) |
|||
self.sync_all() |
|||
self.nodes[1].generate(self.numblocks/2) |
|||
self.sync_all() |
|||
|
|||
# wait for server to finish |
|||
self.t1.join() |
|||
|
|||
# sequence numbers have already been checked in the server's message handler |
|||
|
|||
# sanity check that we have the right number of block hashes and coinbase txids |
|||
assert_equal(len(self.server.blockhashes), self.numblocks) |
|||
assert_equal(len(self.server.txids), self.numblocks) |
|||
|
|||
# verify that each block has the correct coinbase txid |
|||
for i in xrange(0, self.numblocks): |
|||
height = baseheight + i + 1 |
|||
blockhash = self.nodes[0].getblockhash(height) |
|||
assert_equal(blockhash, self.server.blockhashes[i]) |
|||
resp = self.nodes[0].getblock(blockhash) |
|||
coinbase = resp["tx"][0] |
|||
assert_equal(coinbase, self.server.txids[i]) |
|||
|
|||
|
|||
if __name__ == '__main__': |
|||
ProtonTest().main() |
@ -1,21 +0,0 @@ |
|||
// Copyright (c) 2017 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#include "amqpabstractnotifier.h" |
|||
#include "util.h" |
|||
|
|||
|
|||
AMQPAbstractNotifier::~AMQPAbstractNotifier() |
|||
{ |
|||
} |
|||
|
|||
bool AMQPAbstractNotifier::NotifyBlock(const CBlockIndex * /*CBlockIndex*/) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
bool AMQPAbstractNotifier::NotifyTransaction(const CTransaction &/*transaction*/) |
|||
{ |
|||
return true; |
|||
} |
@ -1,43 +0,0 @@ |
|||
// Copyright (c) 2017 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H |
|||
#define ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H |
|||
|
|||
#include "amqpconfig.h" |
|||
|
|||
class CBlockIndex; |
|||
class AMQPAbstractNotifier; |
|||
|
|||
typedef AMQPAbstractNotifier* (*AMQPNotifierFactory)(); |
|||
|
|||
class AMQPAbstractNotifier |
|||
{ |
|||
public: |
|||
AMQPAbstractNotifier() { } |
|||
virtual ~AMQPAbstractNotifier(); |
|||
|
|||
template <typename T> |
|||
static AMQPAbstractNotifier* Create() |
|||
{ |
|||
return new T(); |
|||
} |
|||
|
|||
std::string GetType() const { return type; } |
|||
void SetType(const std::string &t) { type = t; } |
|||
std::string GetAddress() const { return address; } |
|||
void SetAddress(const std::string &a) { address = a; } |
|||
|
|||
virtual bool Initialize() = 0; |
|||
virtual void Shutdown() = 0; |
|||
|
|||
virtual bool NotifyBlock(const CBlockIndex *pindex); |
|||
virtual bool NotifyTransaction(const CTransaction &transaction); |
|||
|
|||
protected: |
|||
std::string type; |
|||
std::string address; |
|||
}; |
|||
|
|||
#endif // ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H
|
@ -1,33 +0,0 @@ |
|||
// Copyright (c) 2017 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef ZCASH_AMQP_AMQPCONFIG_H |
|||
#define ZCASH_AMQP_AMQPCONFIG_H |
|||
|
|||
#if defined(HAVE_CONFIG_H) |
|||
#include "config/bitcoin-config.h" |
|||
#endif |
|||
|
|||
#include <stdarg.h> |
|||
#include <string> |
|||
|
|||
#if ENABLE_PROTON |
|||
#include <proton/connection.hpp> |
|||
#include <proton/connection_options.hpp> |
|||
#include <proton/container.hpp> |
|||
#include <proton/default_container.hpp> |
|||
#include <proton/message.hpp> |
|||
#include <proton/message_id.hpp> |
|||
#include <proton/messaging_handler.hpp> |
|||
#include <proton/thread_safe.hpp> |
|||
#include <proton/tracker.hpp> |
|||
#include <proton/transport.hpp> |
|||
#include <proton/types.hpp> |
|||
#include <proton/url.hpp> |
|||
#endif |
|||
|
|||
#include "primitives/block.h" |
|||
#include "primitives/transaction.h" |
|||
|
|||
#endif // ZCASH_AMQP_AMQPCONFIG_H
|
@ -1,136 +0,0 @@ |
|||
// Copyright (c) 2017 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#include "amqpnotificationinterface.h" |
|||
#include "amqppublishnotifier.h" |
|||
|
|||
#include "version.h" |
|||
#include "main.h" |
|||
#include "streams.h" |
|||
#include "util.h" |
|||
|
|||
// AMQP 1.0 Support
|
|||
//
|
|||
// The boost::signals2 signals and slot system is thread safe, so CValidationInterface listeners
|
|||
// can be invoked from any thread.
|
|||
//
|
|||
// Currently signals are fired from main.cpp so the callbacks should be invoked on the same thread.
|
|||
// It should be safe to share objects responsible for sending, as they should not be run concurrently
|
|||
// across different threads.
|
|||
//
|
|||
// Developers should be mindful of where notifications are fired to avoid potential race conditions.
|
|||
// For example, different signals targeting the same address could be fired from different threads
|
|||
// in different parts of the system around the same time.
|
|||
//
|
|||
// Like the ZMQ notification interface, if a notifier fails to send a message, the notifier is shut down.
|
|||
//
|
|||
|
|||
AMQPNotificationInterface::AMQPNotificationInterface() |
|||
{ |
|||
} |
|||
|
|||
AMQPNotificationInterface::~AMQPNotificationInterface() |
|||
{ |
|||
Shutdown(); |
|||
|
|||
for (std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); i != notifiers.end(); ++i) { |
|||
delete *i; |
|||
} |
|||
} |
|||
|
|||
AMQPNotificationInterface* AMQPNotificationInterface::CreateWithArguments(const std::map<std::string, std::string> &args) |
|||
{ |
|||
AMQPNotificationInterface* notificationInterface = nullptr; |
|||
std::map<std::string, AMQPNotifierFactory> factories; |
|||
std::list<AMQPAbstractNotifier*> notifiers; |
|||
|
|||
factories["pubhashblock"] = AMQPAbstractNotifier::Create<AMQPPublishHashBlockNotifier>; |
|||
factories["pubhashtx"] = AMQPAbstractNotifier::Create<AMQPPublishHashTransactionNotifier>; |
|||
factories["pubrawblock"] = AMQPAbstractNotifier::Create<AMQPPublishRawBlockNotifier>; |
|||
factories["pubrawtx"] = AMQPAbstractNotifier::Create<AMQPPublishRawTransactionNotifier>; |
|||
|
|||
for (std::map<std::string, AMQPNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i) { |
|||
std::map<std::string, std::string>::const_iterator j = args.find("-amqp" + i->first); |
|||
if (j!=args.end()) { |
|||
AMQPNotifierFactory factory = i->second; |
|||
std::string address = j->second; |
|||
AMQPAbstractNotifier *notifier = factory(); |
|||
notifier->SetType(i->first); |
|||
notifier->SetAddress(address); |
|||
notifiers.push_back(notifier); |
|||
} |
|||
} |
|||
|
|||
if (!notifiers.empty()) { |
|||
notificationInterface = new AMQPNotificationInterface(); |
|||
notificationInterface->notifiers = notifiers; |
|||
|
|||
if (!notificationInterface->Initialize()) { |
|||
delete notificationInterface; |
|||
notificationInterface = nullptr; |
|||
} |
|||
} |
|||
|
|||
return notificationInterface; |
|||
} |
|||
|
|||
// Called at startup to conditionally set up
|
|||
bool AMQPNotificationInterface::Initialize() |
|||
{ |
|||
LogPrint("amqp", "amqp: Initialize notification interface\n"); |
|||
|
|||
std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); |
|||
for (; i != notifiers.end(); ++i) { |
|||
AMQPAbstractNotifier *notifier = *i; |
|||
if (notifier->Initialize()) { |
|||
LogPrint("amqp", "amqp: Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress()); |
|||
} else { |
|||
LogPrint("amqp", "amqp: Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress()); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (i != notifiers.end()) { |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
// Called during shutdown sequence
|
|||
void AMQPNotificationInterface::Shutdown() |
|||
{ |
|||
LogPrint("amqp", "amqp: Shutdown notification interface\n"); |
|||
|
|||
for (std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); i != notifiers.end(); ++i) { |
|||
AMQPAbstractNotifier *notifier = *i; |
|||
notifier->Shutdown(); |
|||
} |
|||
} |
|||
|
|||
void AMQPNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex) |
|||
{ |
|||
for (std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); i != notifiers.end(); ) { |
|||
AMQPAbstractNotifier *notifier = *i; |
|||
if (notifier->NotifyBlock(pindex)) { |
|||
i++; |
|||
} else { |
|||
notifier->Shutdown(); |
|||
i = notifiers.erase(i); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void AMQPNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlock *pblock) |
|||
{ |
|||
for (std::list<AMQPAbstractNotifier*>::iterator i = notifiers.begin(); i != notifiers.end(); ) { |
|||
AMQPAbstractNotifier *notifier = *i; |
|||
if (notifier->NotifyTransaction(tx)) { |
|||
i++; |
|||
} else { |
|||
notifier->Shutdown(); |
|||
i = notifiers.erase(i); |
|||
} |
|||
} |
|||
} |
@ -1,36 +0,0 @@ |
|||
// Copyright (c) 2017 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H |
|||
#define ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H |
|||
|
|||
#include "validationinterface.h" |
|||
#include <string> |
|||
#include <map> |
|||
|
|||
class CBlockIndex; |
|||
class AMQPAbstractNotifier; |
|||
|
|||
class AMQPNotificationInterface : public CValidationInterface |
|||
{ |
|||
public: |
|||
virtual ~AMQPNotificationInterface(); |
|||
|
|||
static AMQPNotificationInterface* CreateWithArguments(const std::map<std::string, std::string> &args); |
|||
|
|||
protected: |
|||
bool Initialize(); |
|||
void Shutdown(); |
|||
|
|||
// CValidationInterface
|
|||
void SyncTransaction(const CTransaction &tx, const CBlock *pblock); |
|||
void UpdatedBlockTip(const CBlockIndex *pindex); |
|||
|
|||
private: |
|||
AMQPNotificationInterface(); |
|||
|
|||
std::list<AMQPAbstractNotifier*> notifiers; |
|||
}; |
|||
|
|||
#endif // ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H
|
@ -1,177 +0,0 @@ |
|||
// Copyright (c) 2017 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#include "amqppublishnotifier.h" |
|||
#include "main.h" |
|||
#include "util.h" |
|||
|
|||
#include "amqpsender.h" |
|||
|
|||
#include <memory> |
|||
#include <thread> |
|||
|
|||
static std::multimap<std::string, AMQPAbstractPublishNotifier*> mapPublishNotifiers; |
|||
|
|||
static const char *MSG_HASHBLOCK = "hashblock"; |
|||
static const char *MSG_HASHTX = "hashtx"; |
|||
static const char *MSG_RAWBLOCK = "rawblock"; |
|||
static const char *MSG_RAWTX = "rawtx"; |
|||
|
|||
// Invoke this method from a new thread to run the proton container event loop.
|
|||
void AMQPAbstractPublishNotifier::SpawnProtonContainer() |
|||
{ |
|||
try { |
|||
proton::default_container(*handler_).run(); |
|||
} |
|||
catch (const proton::error_condition &e) { |
|||
LogPrint("amqp", "amqp: container error: %s\n", e.what()); |
|||
} |
|||
catch (const std::runtime_error &e) { |
|||
LogPrint("amqp", "amqp: runtime error: %s\n", e.what()); |
|||
} |
|||
catch (const std::exception &e) { |
|||
LogPrint("amqp", "amqp: exception: %s\n", e.what()); |
|||
} |
|||
catch (...) { |
|||
LogPrint("amqp", "amqp: unknown error\n"); |
|||
} |
|||
handler_->terminate(); |
|||
} |
|||
|
|||
bool AMQPAbstractPublishNotifier::Initialize() |
|||
{ |
|||
std::multimap<std::string, AMQPAbstractPublishNotifier*>::iterator i = mapPublishNotifiers.find(address); |
|||
|
|||
if (i == mapPublishNotifiers.end()) { |
|||
try { |
|||
handler_ = std::make_shared<AMQPSender>(address); |
|||
thread_ = std::make_shared<std::thread>(&AMQPAbstractPublishNotifier::SpawnProtonContainer, this); |
|||
} |
|||
catch (std::exception &e) { |
|||
LogPrint("amqp", "amqp: initialization error: %s\n", e.what()); |
|||
return false; |
|||
} |
|||
mapPublishNotifiers.insert(std::make_pair(address, this)); |
|||
} else { |
|||
// copy the shared ptrs to the message handler and the thread where the proton container is running
|
|||
handler_ = i->second->handler_; |
|||
thread_ = i->second->thread_; |
|||
mapPublishNotifiers.insert(std::make_pair(address, this)); |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void AMQPAbstractPublishNotifier::Shutdown() |
|||
{ |
|||
LogPrint("amqp", "amqp: Shutdown notifier %s at %s\n", GetType(), GetAddress()); |
|||
|
|||
int count = mapPublishNotifiers.count(address); |
|||
|
|||
// remove this notifier from the list of publishers using this address
|
|||
typedef std::multimap<std::string, AMQPAbstractPublishNotifier*>::iterator iterator; |
|||
std::pair<iterator, iterator> iterpair = mapPublishNotifiers.equal_range(address); |
|||
|
|||
for (iterator it = iterpair.first; it != iterpair.second; ++it) { |
|||
if (it->second == this) { |
|||
mapPublishNotifiers.erase(it); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// terminate the connection if this is the last publisher using this address
|
|||
if (count == 1) { |
|||
handler_->terminate(); |
|||
if (thread_.get() != nullptr) { |
|||
if (thread_->joinable()) { |
|||
thread_->join(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
bool AMQPAbstractPublishNotifier::SendMessage(const char *command, const void* data, size_t size) |
|||
{ |
|||
try { |
|||
proton::binary content; |
|||
const char *p = (const char *)data; |
|||
content.assign(p, p + size); |
|||
|
|||
proton::message message(content); |
|||
message.subject(std::string(command)); |
|||
proton::message::property_map & props = message.properties(); |
|||
props.put("x-opt-sequence-number", sequence_); |
|||
handler_->publish(message); |
|||
|
|||
} catch (proton::error_condition &e) { |
|||
LogPrint("amqp", "amqp: error : %s\n", e.what()); |
|||
return false; |
|||
} |
|||
catch (const std::runtime_error &e) { |
|||
LogPrint("amqp", "amqp: runtime error: %s\n", e.what()); |
|||
return false; |
|||
} |
|||
catch (const std::exception &e) { |
|||
LogPrint("amqp", "amqp: exception: %s\n", e.what()); |
|||
return false; |
|||
} |
|||
catch (...) { |
|||
LogPrint("amqp", "amqp: unknown error\n"); |
|||
return false; |
|||
} |
|||
|
|||
sequence_++; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
bool AMQPPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) |
|||
{ |
|||
uint256 hash = pindex->GetBlockHash(); |
|||
LogPrint("amqp", "amqp: Publish hashblock %s\n", hash.GetHex()); |
|||
char data[32]; |
|||
for (unsigned int i = 0; i < 32; i++) |
|||
data[31 - i] = hash.begin()[i]; |
|||
return SendMessage(MSG_HASHBLOCK, data, 32); |
|||
} |
|||
|
|||
bool AMQPPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction) |
|||
{ |
|||
uint256 hash = transaction.GetHash(); |
|||
LogPrint("amqp", "amqp: Publish hashtx %s\n", hash.GetHex()); |
|||
char data[32]; |
|||
for (unsigned int i = 0; i < 32; i++) |
|||
data[31 - i] = hash.begin()[i]; |
|||
return SendMessage(MSG_HASHTX, data, 32); |
|||
} |
|||
|
|||
bool AMQPPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) |
|||
{ |
|||
LogPrint("amqp", "amqp: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); |
|||
|
|||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); |
|||
{ |
|||
LOCK(cs_main); |
|||
CBlock block; |
|||
if(!ReadBlockFromDisk(block, pindex)) { |
|||
LogPrint("amqp", "amqp: Can't read block from disk"); |
|||
return false; |
|||
} |
|||
|
|||
ss << block; |
|||
} |
|||
|
|||
return SendMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size()); |
|||
} |
|||
|
|||
bool AMQPPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction) |
|||
{ |
|||
uint256 hash = transaction.GetHash(); |
|||
LogPrint("amqp", "amqp: Publish rawtx %s\n", hash.GetHex()); |
|||
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); |
|||
ss << transaction; |
|||
return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size()); |
|||
} |
@ -1,56 +0,0 @@ |
|||
// Copyright (c) 2017 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H |
|||
#define ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H |
|||
|
|||
#include "amqpabstractnotifier.h" |
|||
#include "amqpconfig.h" |
|||
#include "amqpsender.h" |
|||
|
|||
#include <memory> |
|||
#include <thread> |
|||
|
|||
class CBlockIndex; |
|||
|
|||
class AMQPAbstractPublishNotifier : public AMQPAbstractNotifier |
|||
{ |
|||
private: |
|||
uint64_t sequence_; // memory only, per notifier instance: upcounting message sequence number
|
|||
|
|||
std::shared_ptr<std::thread> thread_; // proton container thread, may be shared between notifiers
|
|||
std::shared_ptr<AMQPSender> handler_; // proton container message handler, may be shared between notifiers
|
|||
|
|||
public: |
|||
bool SendMessage(const char *command, const void* data, size_t size); |
|||
bool Initialize(); |
|||
void Shutdown(); |
|||
void SpawnProtonContainer(); |
|||
}; |
|||
|
|||
class AMQPPublishHashBlockNotifier : public AMQPAbstractPublishNotifier |
|||
{ |
|||
public: |
|||
bool NotifyBlock(const CBlockIndex *pindex); |
|||
}; |
|||
|
|||
class AMQPPublishHashTransactionNotifier : public AMQPAbstractPublishNotifier |
|||
{ |
|||
public: |
|||
bool NotifyTransaction(const CTransaction &transaction); |
|||
}; |
|||
|
|||
class AMQPPublishRawBlockNotifier : public AMQPAbstractPublishNotifier |
|||
{ |
|||
public: |
|||
bool NotifyBlock(const CBlockIndex *pindex); |
|||
}; |
|||
|
|||
class AMQPPublishRawTransactionNotifier : public AMQPAbstractPublishNotifier |
|||
{ |
|||
public: |
|||
bool NotifyTransaction(const CTransaction &transaction); |
|||
}; |
|||
|
|||
#endif // ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H
|
@ -1,115 +0,0 @@ |
|||
// Copyright (c) 2017 The Zcash developers
|
|||
// Distributed under the MIT software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef ZCASH_AMQP_AMQPSENDER_H |
|||
#define ZCASH_AMQP_AMQPSENDER_H |
|||
|
|||
#include "amqpconfig.h" |
|||
|
|||
#include <deque> |
|||
#include <memory> |
|||
#include <future> |
|||
#include <iostream> |
|||
|
|||
class AMQPSender : public proton::messaging_handler { |
|||
private: |
|||
std::deque<proton::message> messages_; |
|||
proton::url url_; |
|||
proton::connection conn_; |
|||
proton::sender sender_; |
|||
std::mutex lock_; |
|||
std::atomic<bool> terminated_ = {false}; |
|||
|
|||
public: |
|||
|
|||
AMQPSender(const std::string& url) : url_(url) {} |
|||
|
|||
// Callback to initialize the container when run() is invoked
|
|||
void on_container_start(proton::container& c) override { |
|||
proton::duration t(10000); // milliseconds
|
|||
proton::connection_options opts = proton::connection_options().idle_timeout(t); |
|||
conn_ = c.connect(url_, opts); |
|||
sender_ = conn_.open_sender(url_.path()); |
|||
} |
|||
|
|||
// Remote end signals when the local end can send (i.e. has credit)
|
|||
void on_sendable(proton::sender &s) override { |
|||
dispatch(); |
|||
} |
|||
|
|||
// Publish message by adding to queue and trying to dispatch it
|
|||
void publish(const proton::message &m) { |
|||
add_message(m); |
|||
dispatch(); |
|||
} |
|||
|
|||
// Add message to queue
|
|||
void add_message(const proton::message &m) { |
|||
std::lock_guard<std::mutex> guard(lock_); |
|||
messages_.push_back(m); |
|||
} |
|||
|
|||
// Send messages in queue
|
|||
void dispatch() { |
|||
std::lock_guard<std::mutex> guard(lock_); |
|||
|
|||
if (isTerminated()) { |
|||
throw std::runtime_error("amqp connection was terminated"); |
|||
} |
|||
|
|||
if (!conn_.active()) { |
|||
throw std::runtime_error("amqp connection is not active"); |
|||
} |
|||
|
|||
while (messages_.size() > 0) { |
|||
if (sender_.credit()) { |
|||
const proton::message& m = messages_.front(); |
|||
sender_.send(m); |
|||
messages_.pop_front(); |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Close connection to remote end. Container event-loop, by default, will auto-stop.
|
|||
void terminate() { |
|||
std::lock_guard<std::mutex> guard(lock_); |
|||
conn_.close(); |
|||
terminated_.store(true); |
|||
} |
|||
|
|||
bool isTerminated() const { |
|||
return terminated_.load(); |
|||
} |
|||
|
|||
void on_transport_error(proton::transport &t) override { |
|||
t.connection().close(); |
|||
throw t.error(); |
|||
} |
|||
|
|||
void on_connection_error(proton::connection &c) override { |
|||
c.close(); |
|||
throw c.error(); |
|||
} |
|||
|
|||
void on_session_error(proton::session &s) override { |
|||
s.connection().close(); |
|||
throw s.error(); |
|||
} |
|||
|
|||
void on_receiver_error(proton::receiver &r) override { |
|||
r.connection().close(); |
|||
throw r.error(); |
|||
} |
|||
|
|||
void on_sender_error(proton::sender &s) override { |
|||
s.connection().close(); |
|||
throw s.error(); |
|||
} |
|||
|
|||
}; |
|||
|
|||
|
|||
#endif //ZCASH_AMQP_AMQPSENDER_H
|
Loading…
Reference in new issue