diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..8f728f7b2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# This is a skeleton created by zproject. +# You can add hand-written code here. +# See http://editorconfig.org/ and https://github.com/editorconfig/ for +# details about the format and links to plugins for IDEs and editors which +# do not yet support this configuration out of the box - but easily can. + +# This is a top-level setting for project sources under this directory +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +charset = utf-8 + +[*.am] +indent_style = tab diff --git a/bindings/python_cffi/setup.py b/bindings/python_cffi/setup.py index dd1402051..c6355ec6d 100644 --- a/bindings/python_cffi/setup.py +++ b/bindings/python_cffi/setup.py @@ -11,6 +11,13 @@ description = """Python cffi bindings of: an open-source framework for proximity-based p2p apps""", packages = ["zyre_cffi", ], setup_requires=["cffi"], - cffi_modules=["zyre_cffi/build.py:ffibuilder"], + cffi_modules=[ + "zyre_cffi/build.py:ffibuilder", + "zyre_cffi/build.py:ffidestructorbuilder" + ], install_requires=["cffi"], ) +################################################################################ +# THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY # +# Read the zproject/README.md for information about making permanent changes. # +################################################################################ diff --git a/bindings/python_cffi/zyre_cffi/Zyre.py b/bindings/python_cffi/zyre_cffi/Zyre.py new file mode 100644 index 000000000..89597dc89 --- /dev/null +++ b/bindings/python_cffi/zyre_cffi/Zyre.py @@ -0,0 +1,266 @@ +################################################################################ +# THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY # +# Read the zproject/README.md for information about making permanent changes. # +################################################################################ +from .utils import * +from . import native +from . import destructors +libzyre = native.lib +libzyre_destructors = destructors.lib +ffi = native.ffi + +class Zyre(object): + """ + An open-source framework for proximity-based P2P apps + """ + + def __init__(self, name): + """ + Constructor, creates a new Zyre node. Note that until you start the + node it is silent and invisible to other nodes on the network. + The node name is provided to other nodes during discovery. If you + specify NULL, Zyre generates a randomized node name from the UUID. + """ + p = libzyre.zyre_new(self._p, to_bytes(name)) + if p == ffi.NULL: + raise MemoryError("Could not allocate person") + + # ffi.gc returns a copy of the cdata object which will have the + # destructor called when the Python object is GC'd: + # https://cffi.readthedocs.org/en/latest/using.html#ffi-interface + self._p = ffi.gc(p, libzyre_destructors.zyre_destroy_py) + + def uuid(self): + """ + Return our node UUID string, after successful initialization + """ + return libzyre.zyre_uuid(self._p) + + def name(self): + """ + Return our node name, after successful initialization. First 6 + characters of UUID by default. + """ + return libzyre.zyre_name(self._p) + + def set_name(self, name): + """ + Set the public name of this node overriding the default. The name is + provide during discovery and come in each ENTER message. + """ + return libzyre.zyre_set_name(self._p, to_bytes(name)) + + def set_header(self, name, format, ): + """ + Set node header; these are provided to other nodes during discovery + and come in each ENTER message. + """ + return libzyre.zyre_set_header(self._p, to_bytes(name), format, ) + + def set_verbose(self): + """ + Set verbose mode; this tells the node to log all traffic as well as + all major events. + """ + return libzyre.zyre_set_verbose(self._p) + + def set_port(self, port_nbr): + """ + Set UDP beacon discovery port; defaults to 5670, this call overrides + that so you can create independent clusters on the same network, for + e.g. development vs. production. Has no effect after zyre_start(). + """ + return libzyre.zyre_set_port(self._p, port_nbr) + + def set_evasive_timeout(self, interval): + """ + Set the peer evasiveness timeout, in milliseconds. Default is 5000. + This can be tuned in order to deal with expected network conditions + and the response time expected by the application. This is tied to + the beacon interval and rate of messages received. + """ + return libzyre.zyre_set_evasive_timeout(self._p, interval) + + def set_expired_timeout(self, interval): + """ + Set the peer expiration timeout, in milliseconds. Default is 30000. + This can be tuned in order to deal with expected network conditions + and the response time expected by the application. This is tied to + the beacon interval and rate of messages received. + """ + return libzyre.zyre_set_expired_timeout(self._p, interval) + + def set_interval(self, interval): + """ + Set UDP beacon discovery interval, in milliseconds. Default is instant + beacon exploration followed by pinging every 1,000 msecs. + """ + return libzyre.zyre_set_interval(self._p, interval) + + def set_interface(self, value): + """ + Set network interface for UDP beacons. If you do not set this, CZMQ will + choose an interface for you. On boxes with several interfaces you should + specify which one you want to use, or strange things can happen. + """ + return libzyre.zyre_set_interface(self._p, to_bytes(value)) + + def set_endpoint(self, format, ): + """ + By default, Zyre binds to an ephemeral TCP port and broadcasts the local + host name using UDP beaconing. When you call this method, Zyre will use + gossip discovery instead of UDP beaconing. You MUST set-up the gossip + service separately using zyre_gossip_bind() and _connect(). Note that the + endpoint MUST be valid for both bind and connect operations. You can use + inproc://, ipc://, or tcp:// transports (for tcp://, use an IP address + that is meaningful to remote as well as local nodes). Returns 0 if + the bind was successful, else -1. + """ + return libzyre.zyre_set_endpoint(self._p, format, ) + + def gossip_bind(self, format, ): + """ + Set-up gossip discovery of other nodes. At least one node in the cluster + must bind to a well-known gossip endpoint, so other nodes can connect to + it. Note that gossip endpoints are completely distinct from Zyre node + endpoints, and should not overlap (they can use the same transport). + """ + return libzyre.zyre_gossip_bind(self._p, format, ) + + def gossip_connect(self, format, ): + """ + Set-up gossip discovery of other nodes. A node may connect to multiple + other nodes, for redundancy paths. For details of the gossip network + design, see the CZMQ zgossip class. + """ + return libzyre.zyre_gossip_connect(self._p, format, ) + + def start(self): + """ + Start node, after setting header values. When you start a node it + begins discovery and connection. Returns 0 if OK, -1 if it wasn't + possible to start the node. + """ + return libzyre.zyre_start(self._p) + + def stop(self): + """ + Stop node; this signals to other peers that this node will go away. + This is polite; however you can also just destroy the node without + stopping it. + """ + return libzyre.zyre_stop(self._p) + + def join(self, group): + """ + Join a named group; after joining a group you can send messages to + the group and all Zyre nodes in that group will receive them. + """ + return libzyre.zyre_join(self._p, to_bytes(group)) + + def leave(self, group): + """ + Leave a group + """ + return libzyre.zyre_leave(self._p, to_bytes(group)) + + def recv(self): + """ + Receive next message from network; the message may be a control + message (ENTER, EXIT, JOIN, LEAVE) or data (WHISPER, SHOUT). + Returns zmsg_t object, or NULL if interrupted + """ + return libzyre.zyre_recv(self._p) + + def whisper(self, peer, msg_p): + """ + Send message to single peer, specified as a UUID string + Destroys message after sending + """ + return libzyre.zyre_whisper(self._p, to_bytes(peer), msg_p._p) + + def shout(self, group, msg_p): + """ + Send message to a named group + Destroys message after sending + """ + return libzyre.zyre_shout(self._p, to_bytes(group), msg_p._p) + + def whispers(self, peer, format, ): + """ + Send formatted string to a single peer specified as UUID string + """ + return libzyre.zyre_whispers(self._p, to_bytes(peer), format, ) + + def shouts(self, group, format, ): + """ + Send formatted string to a named group + """ + return libzyre.zyre_shouts(self._p, to_bytes(group), format, ) + + def peers(self): + """ + Return zlist of current peer ids. + """ + return libzyre.zyre_peers(self._p) + + def peers_by_group(self, name): + """ + Return zlist of current peers of this group. + """ + return libzyre.zyre_peers_by_group(self._p, to_bytes(name)) + + def own_groups(self): + """ + Return zlist of currently joined groups. + """ + return libzyre.zyre_own_groups(self._p) + + def peer_groups(self): + """ + Return zlist of groups known through connected peers. + """ + return libzyre.zyre_peer_groups(self._p) + + def peer_address(self, peer): + """ + Return the endpoint of a connected peer. + """ + return libzyre.zyre_peer_address(self._p, to_bytes(peer)) + + def peer_header_value(self, peer, name): + """ + Return the value of a header of a conected peer. + Returns null if peer or key doesn't exits. + """ + return libzyre.zyre_peer_header_value(self._p, to_bytes(peer), to_bytes(name)) + + def socket(self): + """ + Return socket for talking to the Zyre node, for polling + """ + return libzyre.zyre_socket(self._p) + + def print(self): + """ + Print zyre node information to stdout + """ + return libzyre.zyre_print(self._p) + + def version(): + """ + Return the Zyre version for run-time API detection; returns + major * 10000 + minor * 100 + patch, as a single integer. + """ + return libzyre.zyre_version() + + def test(verbose): + """ + Self test of this class. + """ + return libzyre.zyre_test(verbose) + +################################################################################ +# THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY # +# Read the zproject/README.md for information about making permanent changes. # +################################################################################ diff --git a/bindings/python_cffi/zyre_cffi/ZyreEvent.py b/bindings/python_cffi/zyre_cffi/ZyreEvent.py new file mode 100644 index 000000000..34409b9e0 --- /dev/null +++ b/bindings/python_cffi/zyre_cffi/ZyreEvent.py @@ -0,0 +1,107 @@ +################################################################################ +# THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY # +# Read the zproject/README.md for information about making permanent changes. # +################################################################################ +from .utils import * +from . import native +from . import destructors +libzyre = native.lib +libzyre_destructors = destructors.lib +ffi = native.ffi + +class ZyreEvent(object): + """ + Parsing Zyre messages + """ + + def __init__(self, node): + """ + Constructor: receive an event from the zyre node, wraps zyre_recv. + The event may be a control message (ENTER, EXIT, JOIN, LEAVE) or + data (WHISPER, SHOUT). + """ + p = libzyre.zyre_event_new(self._p, node._p) + if p == ffi.NULL: + raise MemoryError("Could not allocate person") + + # ffi.gc returns a copy of the cdata object which will have the + # destructor called when the Python object is GC'd: + # https://cffi.readthedocs.org/en/latest/using.html#ffi-interface + self._p = ffi.gc(p, libzyre_destructors.zyre_event_destroy_py) + + def type(self): + """ + Returns event type, as printable uppercase string. Choices are: + "ENTER", "EXIT", "JOIN", "LEAVE", "EVASIVE", "WHISPER" and "SHOUT" + and for the local node: "STOP" + """ + return libzyre.zyre_event_type(self._p) + + def peer_uuid(self): + """ + Return the sending peer's uuid as a string + """ + return libzyre.zyre_event_peer_uuid(self._p) + + def peer_name(self): + """ + Return the sending peer's public name as a string + """ + return libzyre.zyre_event_peer_name(self._p) + + def peer_addr(self): + """ + Return the sending peer's ipaddress as a string + """ + return libzyre.zyre_event_peer_addr(self._p) + + def headers(self): + """ + Returns the event headers, or NULL if there are none + """ + return libzyre.zyre_event_headers(self._p) + + def header(self, name): + """ + Returns value of a header from the message headers + obtained by ENTER. Return NULL if no value was found. + """ + return libzyre.zyre_event_header(self._p, to_bytes(name)) + + def group(self): + """ + Returns the group name that a SHOUT event was sent to + """ + return libzyre.zyre_event_group(self._p) + + def msg(self): + """ + Returns the incoming message payload; the caller can modify the + message but does not own it and should not destroy it. + """ + return libzyre.zyre_event_msg(self._p) + + def get_msg(self): + """ + Returns the incoming message payload, and pass ownership to the + caller. The caller must destroy the message when finished with it. + After called on the given event, further calls will return NULL. + """ + return libzyre.zyre_event_get_msg(self._p) + + def print(self): + """ + Print event to zsys log + """ + return libzyre.zyre_event_print(self._p) + + def test(verbose): + """ + Self test of this class. + """ + return libzyre.zyre_event_test(verbose) + +################################################################################ +# THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY # +# Read the zproject/README.md for information about making permanent changes. # +################################################################################ diff --git a/bindings/python_cffi/zyre_cffi/__init__.py b/bindings/python_cffi/zyre_cffi/__init__.py index 5f43d6c6a..625bec0f9 100644 --- a/bindings/python_cffi/zyre_cffi/__init__.py +++ b/bindings/python_cffi/zyre_cffi/__init__.py @@ -11,3 +11,5 @@ lib = dlopen.lib ffi = dlopen.ffi +from . import Zyre +from . import ZyreEvent diff --git a/bindings/python_cffi/zyre_cffi/build.py b/bindings/python_cffi/zyre_cffi/build.py index b1052dbda..786c1360d 100644 --- a/bindings/python_cffi/zyre_cffi/build.py +++ b/bindings/python_cffi/zyre_cffi/build.py @@ -105,5 +105,32 @@ def kwargs (libname): for item in zyre_cdefs: ffibuilder.cdef(item) +ffidestructorbuilder = cffi.FFI () +ffidestructorbuilder.cdef(''' +void + zyre_destroy_py (void *self); + +void + zyre_event_destroy_py (void *self); + +''') + +ffidestructorbuilder.set_source ("zyre_cffi.destructors", ''' +#include +void +zyre_destroy_py (void *self) +{ + zyre_destroy ((zyre_t **) &self); +} + +void +zyre_event_destroy_py (void *self) +{ + zyre_event_destroy ((zyre_event_t **) &self); +} + +''', **kwargs) + if __name__ == "__main__": ffibuilder.compile (verbose=True) + ffidestructorbuilder.compile (verbose=True) diff --git a/bindings/python_cffi/zyre_cffi/cdefs.py b/bindings/python_cffi/zyre_cffi/cdefs.py index 68a4abf44..5acca6b6b 100644 --- a/bindings/python_cffi/zyre_cffi/cdefs.py +++ b/bindings/python_cffi/zyre_cffi/cdefs.py @@ -3467,6 +3467,13 @@ int zstr_recvx (void *source, char **string_p, ...); +// De-compress and receive C string from socket, received as a message +// with two frames: size of the uncompressed string, and the string itself. +// Caller must free returned string using zstr_free(). Returns NULL if the +// context is being terminated or the process was interrupted. +char * + zstr_recv_compress (void *source); + // Send a C string to a socket, as a frame. The string is sent without // trailing null byte; to read this you can use zstr_recv, or a similar // method that adds a null terminator on the received string. String @@ -3496,6 +3503,20 @@ int zstr_sendx (void *dest, const char *string, ...); +// Compress and send a C string to a socket, as a message with two frames: +// size of the uncompressed string, and the string itself. The string is +// sent without trailing null byte; to read this you can use +// zstr_recv_compress, or a similar method that de-compresses and adds a +// null terminator on the received string. +int + zstr_send_compress (void *dest, const char *string); + +// Compress and send a C string to a socket, as zstr_send_compress(), +// with a MORE flag, so that you can send further strings in the same +// multi-part message. +int + zstr_sendm_compress (void *dest, const char *string); + // Accepts a void pointer and returns a fresh character string. If source // is null, returns an empty string. char * diff --git a/bindings/python_cffi/zyre_cffi/utils.py b/bindings/python_cffi/zyre_cffi/utils.py new file mode 100644 index 000000000..410e4bbdf --- /dev/null +++ b/bindings/python_cffi/zyre_cffi/utils.py @@ -0,0 +1,22 @@ +################################################################################ +# THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY # +# Read the zproject/README.md for information about making permanent changes. # +################################################################################ +try: + text_type = unicode # Python 2 + binary_type = str +except NameError: + text_type = str # Python 3 + binary_type = bytes + + +def to_bytes(s): + return s if isinstance(s, binary_type) else text_type(s).encode("utf-8") + + +def to_unicode(s): + return s if isinstance(s, text_type) else binary_type(s).decode("utf-8") +################################################################################ +# THIS FILE IS 100% GENERATED BY ZPROJECT; DO NOT EDIT EXCEPT EXPERIMENTALLY # +# Read the zproject/README.md for information about making permanent changes. # +################################################################################ diff --git a/ci_build.sh b/ci_build.sh index 1bfe3be9e..96f15b4ff 100755 --- a/ci_build.sh +++ b/ci_build.sh @@ -45,12 +45,12 @@ default|default-Werror|default-with-docs|valgrind) if which ccache && ls -la /usr/lib/ccache ; then HAVE_CCACHE=yes fi + mkdir -p "${CCACHE_DIR}" || HAVE_CCACHE=no if [ "$HAVE_CCACHE" = yes ] && [ -d "$CCACHE_DIR" ]; then echo "CCache stats before build:" ccache -s || true fi - mkdir -p "${HOME}/.ccache" CONFIG_OPTS=() COMMON_CFLAGS="" diff --git a/packaging/debian/control b/packaging/debian/control index b3f81c315..a9eeecbd3 100644 --- a/packaging/debian/control +++ b/packaging/debian/control @@ -14,7 +14,7 @@ Source: zyre Section: net Priority: optional Maintainer: zyre Developers -Standards-Version: 4.0.0 +Standards-Version: 4.0.1.0 Build-Depends: debhelper (>= 9), pkg-config, libzmq3-dev, @@ -54,7 +54,7 @@ Description: runnable binaries from zyre Package: zyre-dbg Architecture: any Section: debug -Priority: extra +Priority: optional Depends: zyre (= ${binary:Version}), ${misc:Depends}