From: Lott, Christopher (cl778h) Date: Thu, 9 Apr 2020 18:49:02 +0000 (-0400) Subject: Extend doc of RMR python binding methods X-Git-Tag: 1.0.1~3 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=4b9552c36d910264474a25cd7c1520a2a816f4d4;p=ric-plt%2Fxapp-frame-py.git Extend doc of RMR python binding methods Also add type hints to function definitions No functional changes Issue-ID: RIC-228 Signed-off-by: Lott, Christopher (cl778h) Change-Id: I709a30a1bf3b3ab52701430ac0f9c01df6dea9d7 --- diff --git a/docs/conf.py b/docs/conf.py index 5b443e9..b92d4d9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -10,3 +10,8 @@ extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode", "numpydoc"] autodoc_member_order = "bysource" linkcheck_ignore = ["http://localhost.*", "http://127.0.0.1.*", "https://gerrit.o-ran-sc.org.*"] +nitpick_ignore = [ + ('py:class', 'ctypes.c_char_p'), + ('py:class', 'ctypes.c_void_p'), + ('py:class', 'ricxappframe.rmr.rmr.LP_rmr_mbuf_t'), + ] diff --git a/docs/rmr_api.rst b/docs/rmr_api.rst index d1f6d98..4db5b7e 100644 --- a/docs/rmr_api.rst +++ b/docs/rmr_api.rst @@ -33,11 +33,161 @@ RMR API .. !! processed by numpydoc !! +.. py:data:: RMR_MAX_RCV_BYTES + :module: ricxappframe.rmr.rmr + :value: 65536 + + + Maximum size message to receive + + + + + + + + + + + + + + + + + .. + !! processed by numpydoc !! + +.. py:data:: RMRFL_MTCALL + :module: ricxappframe.rmr.rmr + :value: 2 + + + Multi-threaded initialization flag + + + + + + + + + + + + + + + + + .. + !! processed by numpydoc !! + +.. py:data:: RMRFL_NONE + :module: ricxappframe.rmr.rmr + :value: 0 + + + Empty flag + + + + + + + + + + + + + + + + + .. + !! processed by numpydoc !! + +.. py:data:: RMR_OK + :module: ricxappframe.rmr.rmr + :value: 0 + + + State constant for OK + + + + + + + + + + + + + + + + + .. + !! processed by numpydoc !! + +.. py:data:: RMR_ERR_TIMEOUT + :module: ricxappframe.rmr.rmr + :value: 12 + + + State constant for timeout + + + + + + + + + + + + + + + + + .. + !! processed by numpydoc !! + +.. py:data:: RMR_ERR_RETRY + :module: ricxappframe.rmr.rmr + :value: 10 + + + State constant for retry + + + + + + + + + + + + + + + + + .. + !! processed by numpydoc !! + .. py:class:: rmr_mbuf_t :module: ricxappframe.rmr.rmr - Reimplementation of rmr_mbuf_t which is in an unaccessible header file (src/common/include/rmr.h) + Mirrors public members of type rmr_mbuf_t from RMR header file src/common/include/rmr.h | typedef struct { | int state; // state of processing @@ -57,11 +207,11 @@ RMR API | int alloc_len; // the length of the allocated space (hdr+payload) | } rmr_mbuf_t; - We do not include the fields we are not supposed to mess with - RE PAYLOADs type below, see the documentation for c_char_p: class ctypes.c_char_p - Represents the C char * datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, POINTER(c_char) must be used. The constructor accepts an integer address, or a bytes object. + Represents the C char * datatype when it points to a zero-terminated string. + For a general character pointer that may also point to binary data, POINTER(c_char) + must be used. The constructor accepts an integer address, or a bytes object. @@ -102,17 +252,32 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_init(uproto_port, max_msg_size, flags) +.. py:function:: rmr_init(uproto_port: ctypes.c_char_p, max_msg_size: int, flags: int) -> ctypes.c_void_p :module: ricxappframe.rmr.rmr - Refer to rmr C documentation for rmr_init - extern void* rmr_init(char* uproto_port, int max_msg_size, int flags) + Prepares the environment for sending and receiving messages. + Refer to RMR C documentation for method:: + + extern void* rmr_init(char* uproto_port, int max_msg_size, int flags) + + This function raises an exception if the returned context is None. + + :Parameters: + + **uproto_port: c_char_p** + Pointer to a buffer with the port number as a string; e.g., "4550" - This python function checks that the context is not None and raises - an excption if it is. + **max_msg_size: integer** + Maximum message size to receive + **flags: integer** + RMR option flags + + :Returns: + c_void_p: + Pointer to RMR context @@ -129,15 +294,24 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_ready(vctx) +.. py:function:: rmr_ready(vctx: ctypes.c_void_p) -> int :module: ricxappframe.rmr.rmr - Refer to rmr C documentation for rmr_ready - extern int rmr_ready(void* vctx) + Checks if a routing table has been received and installed. + Refer to RMR C documentation for method:: + extern int rmr_ready(void* vctx) + :Parameters: + + **vctx: ctypes c_void_p** + Pointer to RMR context + :Returns: + + 1 for yes, 0 for no + .. @@ -154,15 +328,24 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_close(vctx) +.. py:function:: rmr_close(vctx: ctypes.c_void_p) :module: ricxappframe.rmr.rmr - Refer to rmr C documentation for rmr_close - extern void rmr_close(void* vctx) + Closes the listen socket. + Refer to RMR C documentation for method:: + + extern void rmr_close(void* vctx) + :Parameters: + **vctx: ctypes c_void_p** + Pointer to RMR context + :Returns: + + None + .. @@ -179,15 +362,27 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_set_stimeout(vctx, time) +.. py:function:: rmr_set_stimeout(vctx: ctypes.c_void_p, rloops: int) -> int :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_set_stimeout - extern int rmr_set_stimeout(void* vctx, int time) + Sets the configuration for how RMR will retry message send operations. + Refer to RMR C documentation for method:: + + extern int rmr_set_stimeout(void* vctx, int rloops) + + :Parameters: + + **vctx: ctypes c_void_p** + Pointer to RMR context + **rloops: int** + Number of retry loops + :Returns: + 0 on success, -1 on failure + .. @@ -204,22 +399,51 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_alloc_msg(vctx, size, payload=None, gen_transaction_id=False, mtype=None, meid=None, sub_id=None, fixed_transaction_id=None) +.. py:function:: rmr_alloc_msg(vctx: ctypes.c_void_p, size: int, payload=None, gen_transaction_id: bool = False, mtype=None, meid=None, sub_id=None, fixed_transaction_id=None) :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_alloc_msg - extern rmr_mbuf_t* rmr_alloc_msg(void* vctx, int size) + Allocates and returns a buffer to write and send through the RMR library. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_alloc_msg(void* vctx, int size) + + Optionally populates the message from the remaining arguments. + TODO: on next API break, clean up transaction_id ugliness. Kept for now to preserve API. - if payload is not None, attempts to set the payload - if gen_transaction_id is True, it generates and sets a transaction id. Note, fixed_transaction_id supersedes this option - if mtype is not None, sets the sbuf's message type - if meid is not None, sets the sbuf's meid - if sub_id is not None, sets the sbud's subscription id - if fixed_transaction_id is set, it deterministically sets the transaction_id. This overrides the option gen_transation_id + :Parameters: + + **vctx: ctypes c_void_p** + Pointer to RMR context + + **size: int** + How much space to allocate + + **payload: bytes** + if not None, attempts to set the payload + + **gen_transaction_id: bool** + if True, generates and sets a transaction ID. + Note, option fixed_transaction_id overrides this option + + **mtype: bytes** + if not None, sets the sbuf's message type + + **meid: bytes** + if not None, sets the sbuf's meid + + **sub_id: bytes** + if not None, sets the sbuf's subscription id + **fixed_transaction_id: bytes** + if not None, used as the transaction ID. + Note, this overrides the option gen_transaction_id + :Returns: + + c_void_p: + Pointer to rmr_mbuf structure @@ -236,15 +460,33 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_realloc_payload(ptr_mbuf, new_len, copy=False, clone=False) +.. py:function:: rmr_realloc_payload(ptr_mbuf: ctypes.c_void_p, new_len: int, copy: bool = False, clone: bool = False) :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_realloc_payload(). - extern rmr_mbuf_t* rmr_realloc_payload(rmr_mbuf_t*, int, int, int) + Allocates and returns a message buffer large enough for the new length. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_realloc_payload(rmr_mbuf_t*, int, int, int) + + :Parameters: + + **ptr_mbuf: c_void_p** + Pointer to rmr_mbuf structure + + **new_len: int** + Length + **copy: bool** + Whether to copy the original paylod + **clone: bool** + Whether to clone the original buffer + :Returns: + + c_void_p: + Pointer to rmr_mbuf structure @@ -261,15 +503,24 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_free_msg(mbuf) +.. py:function:: rmr_free_msg(ptr_mbuf: ctypes.c_void_p) :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_free_msg - extern void rmr_free_msg(rmr_mbuf_t* mbuf ) + Releases the message buffer. + Refer to RMR C documentation for method:: + + extern void rmr_free_msg(rmr_mbuf_t* mbuf ) + + :Parameters: + **ptr_mbuf: c_void_p** + Pointer to rmr_mbuf structure + :Returns: + None + .. @@ -286,15 +537,24 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_payload_size(ptr_mbuf) +.. py:function:: rmr_payload_size(ptr_mbuf: ctypes.c_void_p) -> int :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_payload_size - extern int rmr_payload_size(rmr_mbuf_t* msg) + Gets the number of bytes available in the payload. + Refer to RMR C documentation for method:: + extern int rmr_payload_size(rmr_mbuf_t* msg) + :Parameters: + **ptr_mbuf: c_void_p** + Pointer to rmr_mbuf structure + + :Returns: + + int: + Number of bytes available @@ -311,15 +571,27 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_send_msg(vctx, ptr_mbuf) +.. py:function:: rmr_send_msg(vctx: ctypes.c_void_p, ptr_mbuf: ricxappframe.rmr.rmr.LP_rmr_mbuf_t) -> ricxappframe.rmr.rmr.LP_rmr_mbuf_t :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_send_msg - extern rmr_mbuf_t* rmr_send_msg(void* vctx, rmr_mbuf_t* msg) + Sends the message according to the routing table and returns an empty buffer. + Refer to RMR C documentation for method:: + extern rmr_mbuf_t* rmr_send_msg(void* vctx, rmr_mbuf_t* msg) + + :Parameters: + **vctx: ctypes c_void_p** + Pointer to RMR context + + **ptr_mbuf: c_void_p** + Pointer to rmr_mbuf structure + + :Returns: + c_void_p: + Pointer to rmr_mbuf structure @@ -336,15 +608,27 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_rcv_msg(vctx, ptr_mbuf) +.. py:function:: rmr_rcv_msg(vctx: ctypes.c_void_p, ptr_mbuf: ricxappframe.rmr.rmr.LP_rmr_mbuf_t) -> ricxappframe.rmr.rmr.LP_rmr_mbuf_t :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_rcv_msg - extern rmr_mbuf_t* rmr_rcv_msg(void* vctx, rmr_mbuf_t* old_msg) + Waits for a message to arrive, and returns it. + Refer to RMR C documentation for method:: + extern rmr_mbuf_t* rmr_rcv_msg(void* vctx, rmr_mbuf_t* old_msg) + :Parameters: + + **vctx: ctypes c_void_p** + Pointer to RMR context + **ptr_mbuf: c_void_p** + Pointer to rmr_mbuf structure + + :Returns: + + c_void_p: + Pointer to rmr_mbuf structure @@ -361,15 +645,30 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_torcv_msg(vctx, ptr_mbuf, ms_to) +.. py:function:: rmr_torcv_msg(vctx: ctypes.c_void_p, ptr_mbuf: ricxappframe.rmr.rmr.LP_rmr_mbuf_t, ms_to: int) -> ricxappframe.rmr.rmr.LP_rmr_mbuf_t :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_torcv_msg - extern rmr_mbuf_t* rmr_torcv_msg(void* vctx, rmr_mbuf_t* old_msg, int ms_to) + Waits up to the timeout value for a message to arrive, and returns it. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_torcv_msg(void* vctx, rmr_mbuf_t* old_msg, int ms_to) + + :Parameters: + + **vctx: ctypes c_void_p** + Pointer to RMR context + **ptr_mbuf: c_void_p** + Pointer to rmr_mbuf structure + **ms_to: int** + Time out value in milliseconds + + :Returns: + c_void_p: + Pointer to rmr_mbuf structure @@ -386,18 +685,37 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_rts_msg(vctx, ptr_mbuf, payload=None, mtype=None) +.. py:function:: rmr_rts_msg(vctx: ctypes.c_void_p, ptr_mbuf: ricxappframe.rmr.rmr.LP_rmr_mbuf_t, payload=None, mtype=None) -> ricxappframe.rmr.rmr.LP_rmr_mbuf_t :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_rts_msg - extern rmr_mbuf_t* rmr_rts_msg(void* vctx, rmr_mbuf_t* msg) + Sends a message to the originating endpoint and returns an empty buffer. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_rts_msg(void* vctx, rmr_mbuf_t* msg) additional features beyond c-rmr: if payload is not None, attempts to set the payload if mtype is not None, sets the sbuf's message type + :Parameters: + **vctx: ctypes c_void_p** + Pointer to an RMR context + + **ptr_mbuf: ctypes c_void_p** + Pointer to an RMR message buffer + + **payload: bytes** + Payload + + **mtype: bytes** + Message type + + :Returns: + + c_void_p: + Pointer to rmr_mbuf structure @@ -414,15 +732,24 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_call(vctx, ptr_mbuf) +.. py:function:: rmr_call(vctx: ctypes.c_void_p, ptr_mbuf: ricxappframe.rmr.rmr.LP_rmr_mbuf_t) -> ricxappframe.rmr.rmr.LP_rmr_mbuf_t :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_call - extern rmr_mbuf_t* rmr_call(void* vctx, rmr_mbuf_t* msg) + Sends a message, waits for a response and returns it. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_call(void* vctx, rmr_mbuf_t* msg) + :Parameters: + + **ptr_mbuf: ctypes c_void_p** + Pointer to an RMR message buffer + :Returns: + c_void_p: + Pointer to rmr_mbuf structure @@ -439,19 +766,32 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_set_meid(ptr_mbuf, byte_str) +.. py:function:: rmr_set_meid(ptr_mbuf: ricxappframe.rmr.rmr.LP_rmr_mbuf_t, byte_str: bytes) -> int :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_bytes2meid - extern int rmr_bytes2meid(rmr_mbuf_t* mbuf, unsigned char const* src, int len); + Sets the managed entity field in the message and returns the number of bytes copied. + Refer to RMR C documentation for method:: + + extern int rmr_bytes2meid(rmr_mbuf_t* mbuf, unsigned char const* src, int len); Caution: the meid length supported in an RMR message is 32 bytes, but C applications expect this to be a nil terminated string and thus only 31 bytes are actually available. Raises: exceptions.MeidSizeOutOfRang + :Parameters: + + **ptr_mbuf: ctypes c_void_p** + Pointer to an RMR message buffer + + **byte_tr: bytes** + Managed entity ID value + + :Returns: + int: + number of bytes copied @@ -468,22 +808,24 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_get_meid(ptr_mbuf) +.. py:function:: rmr_get_meid(ptr_mbuf: ricxappframe.rmr.rmr.LP_rmr_mbuf_t) -> bytes :module: ricxappframe.rmr.rmr - Get the managed equipment ID (meid) from the message header. + Gets the managed entity ID (meid) from the message header. + This is a python-friendly version of RMR C method:: + extern unsigned char* rmr_get_meid(rmr_mbuf_t* mbuf, unsigned char* dest); :Parameters: **ptr_mbuf: ctypes c_void_p** - Pointer to an rmr message buffer + Pointer to an RMR message buffer :Returns: - string: - meid + bytes: + Managed entity ID @@ -500,15 +842,27 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: rmr_get_src(ptr_mbuf, dest) +.. py:function:: rmr_get_src(ptr_mbuf: ricxappframe.rmr.rmr.LP_rmr_mbuf_t, dest: ctypes.c_char_p) -> ctypes.c_char_p :module: ricxappframe.rmr.rmr - Refer to the rmr C documentation for rmr_get_src - extern unsigned char* rmr_get_src(rmr_mbuf_t* mbuf, unsigned char* dest); + Copies the message-source information to the buffer. + Refer to RMR C documentation for method:: + extern unsigned char* rmr_get_src(rmr_mbuf_t* mbuf, unsigned char* dest); + :Parameters: + + **ptr_mbuf: ctypes POINTER(rmr_mbuf_t)** + Pointer to an RMR message buffer + **dest: ctypes c_char_p** + Pointer to a buffer to receive the message source + + :Returns: + + string: + message-source information @@ -525,11 +879,11 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: get_payload(ptr_mbuf) +.. py:function:: get_payload(ptr_mbuf: ctypes.c_void_p) -> bytes :module: ricxappframe.rmr.rmr - Given a rmr_buf_t*, get it's binary payload as a bytes object + Gets the binary payload from the rmr_buf_t*. :Parameters: @@ -557,11 +911,11 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: get_xaction(ptr_mbuf) +.. py:function:: get_xaction(ptr_mbuf: ctypes.c_void_p) -> bytes :module: ricxappframe.rmr.rmr - given a rmr_buf_t*, get it's transaction id + Gets the transaction ID from the rmr_buf_t*. :Parameters: @@ -589,11 +943,11 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: message_summary(ptr_mbuf) +.. py:function:: message_summary(ptr_mbuf: ctypes.c_void_p) -> dict :module: ricxappframe.rmr.rmr - Returns a dict that contains the fields of a message + Returns a dict with the fields of an RMR message. :Parameters: @@ -621,12 +975,12 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: set_payload_and_length(byte_str, ptr_mbuf) +.. py:function:: set_payload_and_length(byte_str: bytes, ptr_mbuf: ctypes.c_void_p) :module: ricxappframe.rmr.rmr - | Set an rmr payload and content length - | In place method, no return + Sets an rmr payload and content length. + In place method, no return. :Parameters: @@ -653,11 +1007,11 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: generate_and_set_transaction_id(ptr_mbuf) +.. py:function:: generate_and_set_transaction_id(ptr_mbuf: ctypes.c_void_p) :module: ricxappframe.rmr.rmr - Generate a UUID and Set an rmr transaction id to it + Generates a UUID and sets the RMR transaction id to it :Parameters: @@ -681,11 +1035,11 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: set_transaction_id(ptr_mbuf, tid_bytes) +.. py:function:: set_transaction_id(ptr_mbuf: ctypes.c_void_p, tid_bytes: bytes) :module: ricxappframe.rmr.rmr - Set an rmr transaction id + Sets an RMR transaction id TODO: on next API break, merge these two functions. Not done now to preserve API. @@ -713,11 +1067,11 @@ RMR API .. !! processed by numpydoc !! -.. py:function:: get_src(ptr_mbuf) +.. py:function:: get_src(ptr_mbuf: ctypes.c_void_p) -> str :module: ricxappframe.rmr.rmr - Get the message source (likely host:port) + Gets the message source (likely host:port) :Parameters: @@ -744,3 +1098,4 @@ RMR API .. !! processed by numpydoc !! + diff --git a/ricxappframe/rmr/rmr.py b/ricxappframe/rmr/rmr.py index 39a0245..80617a7 100644 --- a/ricxappframe/rmr/rmr.py +++ b/ricxappframe/rmr/rmr.py @@ -1,4 +1,3 @@ -# vim: expandtab ts=4 sw=4: # ================================================================================== # Copyright (c) 2019-2020 Nokia # Copyright (c) 2018-2020 AT&T Intellectual Property. @@ -17,16 +16,14 @@ # ================================================================================== import uuid import json -from ctypes import RTLD_GLOBAL, Structure, c_int, POINTER, c_char, c_char_p, c_void_p, memmove, cast -from ctypes import CDLL -from ctypes import create_string_buffer +from ctypes import CDLL, POINTER, RTLD_GLOBAL, Structure +from ctypes import c_char, c_char_p, c_int, c_void_p, cast, create_string_buffer, memmove + from ricxappframe.rmr.exceptions import BadBufferAllocation, MeidSizeOutOfRange, InitFailed # https://docs.python.org/3.7/library/ctypes.html # https://stackoverflow.com/questions/2327344/ctypes-loading-a-c-shared-library-that-has-dependencies/30845750#30845750 # make sure you do a set -x LD_LIBRARY_PATH /usr/local/lib/; - -# even though we don't use these directly, they contain symbols we need rmr_c_lib = CDLL("librmr_si.so", mode=RTLD_GLOBAL) @@ -38,9 +35,9 @@ _rmr_const.argtypes = [] _rmr_const.restype = c_char_p -def _get_constants(cache={}): +def _get_constants(cache={}) -> dict: """ - Get or build needed constants from rmr + Gets constants published by RMR and caches for subsequent calls. TODO: are there constants that end user applications need? """ if cache: @@ -51,9 +48,10 @@ def _get_constants(cache={}): return cache -def _get_mapping_dict(cache={}): +def _get_mapping_dict(cache={}) -> dict: """ - Get or build the state mapping dict + Builds a state mapping dict from constants and caches for subsequent calls. + Relevant constants at this writing include: RMR_OK 0 state is good RMR_ERR_BADARG 1 argument passd to function was unusable @@ -85,9 +83,10 @@ def _get_mapping_dict(cache={}): return cache -def _state_to_status(stateno): +def _state_to_status(stateno: int) -> str: """ - Convert a msg state to status + Converts a msg state integer to a status string. + Returns "UNKNOWN STATE" if the int value is not known. """ sdict = _get_mapping_dict() @@ -105,17 +104,23 @@ _RCONST = _get_constants() # These constants are directly usable by importers of this library # TODO: Are there others that will be useful? +#: Maximum size message to receive RMR_MAX_RCV_BYTES = _RCONST["RMR_MAX_RCV_BYTES"] +#: Multi-threaded initialization flag RMRFL_MTCALL = _RCONST.get("RMRFL_MTCALL", 0x02) # initialization flags +#: Empty flag RMRFL_NONE = _RCONST.get("RMRFL_NONE", 0x0) -RMR_OK = _RCONST["RMR_OK"] # useful state constants +#: State constant for OK +RMR_OK = _RCONST["RMR_OK"] +#: State constant for timeout RMR_ERR_TIMEOUT = _RCONST["RMR_ERR_TIMEOUT"] +#: State constant for retry RMR_ERR_RETRY = _RCONST["RMR_ERR_RETRY"] class rmr_mbuf_t(Structure): """ - Reimplementation of rmr_mbuf_t which is in an unaccessible header file (src/common/include/rmr.h) + Mirrors public members of type rmr_mbuf_t from RMR header file src/common/include/rmr.h | typedef struct { | int state; // state of processing @@ -135,21 +140,19 @@ class rmr_mbuf_t(Structure): | int alloc_len; // the length of the allocated space (hdr+payload) | } rmr_mbuf_t; - We do not include the fields we are not supposed to mess with - RE PAYLOADs type below, see the documentation for c_char_p: class ctypes.c_char_p - Represents the C char * datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, POINTER(c_char) must be used. The constructor accepts an integer address, or a bytes object. + Represents the C char * datatype when it points to a zero-terminated string. + For a general character pointer that may also point to binary data, POINTER(c_char) + must be used. The constructor accepts an integer address, or a bytes object. """ _fields_ = [ ("state", c_int), ("mtype", c_int), ("len", c_int), - ( - "payload", - POINTER(c_char), - ), # according to th following the python bytes are already unsinged https://bytes.com/topic/python/answers/695078-ctypes-unsigned-char + ("payload", POINTER(c_char)), # according to the following the python bytes are already unsigned + # https://bytes.com/topic/python/answers/695078-ctypes-unsigned-char ("xaction", POINTER(c_char)), ("sub_id", c_int), ("tp_state", c_int), @@ -164,13 +167,28 @@ _rmr_init.argtypes = [c_char_p, c_int, c_int] _rmr_init.restype = c_void_p -def rmr_init(uproto_port, max_msg_size, flags): +def rmr_init(uproto_port: c_char_p, max_msg_size: int, flags: int) -> c_void_p: """ - Refer to rmr C documentation for rmr_init - extern void* rmr_init(char* uproto_port, int max_msg_size, int flags) + Prepares the environment for sending and receiving messages. + Refer to RMR C documentation for method:: + + extern void* rmr_init(char* uproto_port, int max_msg_size, int flags) + + This function raises an exception if the returned context is None. + + Parameters + ---------- + uproto_port: c_char_p + Pointer to bytes built from the port number as a string; e.g., b'4550' + max_msg_size: integer + Maximum message size to receive + flags: integer + RMR option flags - This python function checks that the context is not None and raises - an excption if it is. + Returns + ------- + c_void_p: + Pointer to RMR context """ mrc = _rmr_init(uproto_port, max_msg_size, flags) if mrc is None: @@ -183,10 +201,21 @@ _rmr_ready.argtypes = [c_void_p] _rmr_ready.restype = c_int -def rmr_ready(vctx): +def rmr_ready(vctx: c_void_p) -> int: """ - Refer to rmr C documentation for rmr_ready - extern int rmr_ready(void* vctx) + Checks if a routing table has been received and installed. + Refer to RMR C documentation for method:: + + extern int rmr_ready(void* vctx) + + Parameters + ---------- + vctx: ctypes c_void_p + Pointer to RMR context + + Returns + ------- + 1 for yes, 0 for no """ return _rmr_ready(vctx) @@ -195,12 +224,23 @@ _rmr_close = rmr_c_lib.rmr_close _rmr_close.argtypes = [c_void_p] -def rmr_close(vctx): +def rmr_close(vctx: c_void_p): """ - Refer to rmr C documentation for rmr_close - extern void rmr_close(void* vctx) + Closes the listen socket. + Refer to RMR C documentation for method:: + + extern void rmr_close(void* vctx) + + Parameters + ---------- + vctx: ctypes c_void_p + Pointer to RMR context + + Returns + ------- + None """ - return _rmr_close(vctx) + _rmr_close(vctx) _rmr_set_stimeout = rmr_c_lib.rmr_set_stimeout @@ -208,12 +248,25 @@ _rmr_set_stimeout.argtypes = [c_void_p, c_int] _rmr_set_stimeout.restype = c_int -def rmr_set_stimeout(vctx, time): +def rmr_set_stimeout(vctx: c_void_p, rloops: int) -> int: """ - Refer to the rmr C documentation for rmr_set_stimeout - extern int rmr_set_stimeout(void* vctx, int time) + Sets the configuration for how RMR will retry message send operations. + Refer to RMR C documentation for method:: + + extern int rmr_set_stimeout(void* vctx, int rloops) + + Parameters + ---------- + vctx: ctypes c_void_p + Pointer to RMR context + rloops: int + Number of retry loops + + Returns + ------- + 0 on success, -1 on failure """ - return _rmr_set_stimeout(vctx, time) + return _rmr_set_stimeout(vctx, rloops) _rmr_alloc_msg = rmr_c_lib.rmr_alloc_msg @@ -221,21 +274,44 @@ _rmr_alloc_msg.argtypes = [c_void_p, c_int] _rmr_alloc_msg.restype = POINTER(rmr_mbuf_t) -def rmr_alloc_msg( - vctx, size, payload=None, gen_transaction_id=False, mtype=None, meid=None, sub_id=None, fixed_transaction_id=None -): +def rmr_alloc_msg(vctx: c_void_p, size: int, + payload=None, gen_transaction_id=False, mtype=None, + meid=None, sub_id=None, fixed_transaction_id=None): """ - Refer to the rmr C documentation for rmr_alloc_msg - extern rmr_mbuf_t* rmr_alloc_msg(void* vctx, int size) + Allocates and returns a buffer to write and send through the RMR library. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_alloc_msg(void* vctx, int size) + + Optionally populates the message from the remaining arguments. + TODO: on next API break, clean up transaction_id ugliness. Kept for now to preserve API. - if payload is not None, attempts to set the payload - if gen_transaction_id is True, it generates and sets a transaction id. Note, fixed_transaction_id supersedes this option - if mtype is not None, sets the sbuf's message type - if meid is not None, sets the sbuf's meid - if sub_id is not None, sets the sbud's subscription id - if fixed_transaction_id is set, it deterministically sets the transaction_id. This overrides the option gen_transation_id + Parameters + ---------- + vctx: ctypes c_void_p + Pointer to RMR context + size: int + How much space to allocate + payload: bytes + if not None, attempts to set the payload + gen_transaction_id: bool + if True, generates and sets a transaction ID. + Note, option fixed_transaction_id overrides this option + mtype: bytes + if not None, sets the sbuf's message type + meid: bytes + if not None, sets the sbuf's meid + sub_id: bytes + if not None, sets the sbuf's subscription id + fixed_transaction_id: bytes + if not None, used as the transaction ID. + Note, this overrides the option gen_transaction_id + Returns + ------- + c_void_p: + Pointer to rmr_mbuf structure """ sbuf = _rmr_alloc_msg(vctx, size) try: @@ -271,26 +347,55 @@ _rmr_realloc_payload.argtypes = [POINTER(rmr_mbuf_t), c_int, c_int, c_int] # ne _rmr_realloc_payload.restype = POINTER(rmr_mbuf_t) -def rmr_realloc_payload(ptr_mbuf, new_len, copy=False, clone=False): +def rmr_realloc_payload(ptr_mbuf: c_void_p, new_len: int, copy=False, clone=False): """ - Refer to the rmr C documentation for rmr_realloc_payload(). - extern rmr_mbuf_t* rmr_realloc_payload(rmr_mbuf_t*, int, int, int) + Allocates and returns a message buffer large enough for the new length. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_realloc_payload(rmr_mbuf_t*, int, int, int) + + Parameters + ---------- + ptr_mbuf: c_void_p + Pointer to rmr_mbuf structure + new_len: int + Length + copy: bool + Whether to copy the original paylod + clone: bool + Whether to clone the original buffer + + Returns + ------- + c_void_p: + Pointer to rmr_mbuf structure """ return _rmr_realloc_payload(ptr_mbuf, new_len, copy, clone) _rmr_free_msg = rmr_c_lib.rmr_free_msg -_rmr_free_msg.argtypes = [c_void_p] +_rmr_free_msg.argtypes = [POINTER(rmr_mbuf_t)] _rmr_free_msg.restype = None -def rmr_free_msg(mbuf): +def rmr_free_msg(ptr_mbuf: c_void_p): """ - Refer to the rmr C documentation for rmr_free_msg - extern void rmr_free_msg(rmr_mbuf_t* mbuf ) + Releases the message buffer. + Refer to RMR C documentation for method:: + + extern void rmr_free_msg(rmr_mbuf_t* mbuf ) + + Parameters + ---------- + ptr_mbuf: c_void_p + Pointer to rmr_mbuf structure + + Returns + ------- + None """ - if mbuf is not None: - _rmr_free_msg(mbuf) + if ptr_mbuf is not None: + _rmr_free_msg(ptr_mbuf) _rmr_payload_size = rmr_c_lib.rmr_payload_size @@ -298,10 +403,22 @@ _rmr_payload_size.argtypes = [POINTER(rmr_mbuf_t)] _rmr_payload_size.restype = c_int -def rmr_payload_size(ptr_mbuf): +def rmr_payload_size(ptr_mbuf: c_void_p) -> int: """ - Refer to the rmr C documentation for rmr_payload_size - extern int rmr_payload_size(rmr_mbuf_t* msg) + Gets the number of bytes available in the payload. + Refer to RMR C documentation for method:: + + extern int rmr_payload_size(rmr_mbuf_t* msg) + + Parameters + ---------- + ptr_mbuf: c_void_p + Pointer to rmr_mbuf structure + + Returns + ------- + int: + Number of bytes available """ return _rmr_payload_size(ptr_mbuf) @@ -315,10 +432,24 @@ _rmr_send_msg.argtypes = [c_void_p, POINTER(rmr_mbuf_t)] _rmr_send_msg.restype = POINTER(rmr_mbuf_t) -def rmr_send_msg(vctx, ptr_mbuf): +def rmr_send_msg(vctx: c_void_p, ptr_mbuf: POINTER(rmr_mbuf_t)) -> POINTER(rmr_mbuf_t): """ - Refer to the rmr C documentation for rmr_send_msg - extern rmr_mbuf_t* rmr_send_msg(void* vctx, rmr_mbuf_t* msg) + Sends the message according to the routing table and returns an empty buffer. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_send_msg(void* vctx, rmr_mbuf_t* msg) + + Parameters + ---------- + vctx: ctypes c_void_p + Pointer to RMR context + ptr_mbuf: c_void_p + Pointer to rmr_mbuf structure + + Returns + ------- + c_void_p: + Pointer to rmr_mbuf structure """ return _rmr_send_msg(vctx, ptr_mbuf) @@ -329,10 +460,24 @@ _rmr_rcv_msg.argtypes = [c_void_p, POINTER(rmr_mbuf_t)] _rmr_rcv_msg.restype = POINTER(rmr_mbuf_t) -def rmr_rcv_msg(vctx, ptr_mbuf): +def rmr_rcv_msg(vctx: c_void_p, ptr_mbuf: POINTER(rmr_mbuf_t)) -> POINTER(rmr_mbuf_t): """ - Refer to the rmr C documentation for rmr_rcv_msg - extern rmr_mbuf_t* rmr_rcv_msg(void* vctx, rmr_mbuf_t* old_msg) + Waits for a message to arrive, and returns it. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_rcv_msg(void* vctx, rmr_mbuf_t* old_msg) + + Parameters + ---------- + vctx: ctypes c_void_p + Pointer to RMR context + ptr_mbuf: c_void_p + Pointer to rmr_mbuf structure + + Returns + ------- + c_void_p: + Pointer to rmr_mbuf structure """ return _rmr_rcv_msg(vctx, ptr_mbuf) @@ -342,10 +487,26 @@ _rmr_torcv_msg.argtypes = [c_void_p, POINTER(rmr_mbuf_t), c_int] _rmr_torcv_msg.restype = POINTER(rmr_mbuf_t) -def rmr_torcv_msg(vctx, ptr_mbuf, ms_to): +def rmr_torcv_msg(vctx: c_void_p, ptr_mbuf: POINTER(rmr_mbuf_t), ms_to: int) -> POINTER(rmr_mbuf_t): """ - Refer to the rmr C documentation for rmr_torcv_msg - extern rmr_mbuf_t* rmr_torcv_msg(void* vctx, rmr_mbuf_t* old_msg, int ms_to) + Waits up to the timeout value for a message to arrive, and returns it. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_torcv_msg(void* vctx, rmr_mbuf_t* old_msg, int ms_to) + + Parameters + ---------- + vctx: ctypes c_void_p + Pointer to RMR context + ptr_mbuf: c_void_p + Pointer to rmr_mbuf structure + ms_to: int + Time out value in milliseconds + + Returns + ------- + c_void_p: + Pointer to rmr_mbuf structure """ return _rmr_torcv_msg(vctx, ptr_mbuf, ms_to) @@ -355,14 +516,32 @@ _rmr_rts_msg.argtypes = [c_void_p, POINTER(rmr_mbuf_t)] _rmr_rts_msg.restype = POINTER(rmr_mbuf_t) -def rmr_rts_msg(vctx, ptr_mbuf, payload=None, mtype=None): +def rmr_rts_msg(vctx: c_void_p, ptr_mbuf: POINTER(rmr_mbuf_t), payload=None, mtype=None) -> POINTER(rmr_mbuf_t): """ - Refer to the rmr C documentation for rmr_rts_msg - extern rmr_mbuf_t* rmr_rts_msg(void* vctx, rmr_mbuf_t* msg) + Sends a message to the originating endpoint and returns an empty buffer. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_rts_msg(void* vctx, rmr_mbuf_t* msg) additional features beyond c-rmr: if payload is not None, attempts to set the payload if mtype is not None, sets the sbuf's message type + + Parameters + ---------- + vctx: ctypes c_void_p + Pointer to an RMR context + ptr_mbuf: ctypes c_void_p + Pointer to an RMR message buffer + payload: bytes + Payload + mtype: bytes + Message type + + Returns + ------- + c_void_p: + Pointer to rmr_mbuf structure """ if payload: @@ -379,10 +558,22 @@ _rmr_call.argtypes = [c_void_p, POINTER(rmr_mbuf_t)] _rmr_call.restype = POINTER(rmr_mbuf_t) -def rmr_call(vctx, ptr_mbuf): +def rmr_call(vctx: c_void_p, ptr_mbuf: POINTER(rmr_mbuf_t)) -> POINTER(rmr_mbuf_t): """ - Refer to the rmr C documentation for rmr_call - extern rmr_mbuf_t* rmr_call(void* vctx, rmr_mbuf_t* msg) + Sends a message, waits for a response and returns it. + Refer to RMR C documentation for method:: + + extern rmr_mbuf_t* rmr_call(void* vctx, rmr_mbuf_t* msg) + + Parameters + ---------- + ptr_mbuf: ctypes c_void_p + Pointer to an RMR message buffer + + Returns + ------- + c_void_p: + Pointer to rmr_mbuf structure """ return _rmr_call(vctx, ptr_mbuf) @@ -392,15 +583,29 @@ _rmr_bytes2meid.argtypes = [POINTER(rmr_mbuf_t), c_char_p, c_int] _rmr_bytes2meid.restype = c_int -def rmr_set_meid(ptr_mbuf, byte_str): +def rmr_set_meid(ptr_mbuf: POINTER(rmr_mbuf_t), byte_str: bytes) -> int: """ - Refer to the rmr C documentation for rmr_bytes2meid - extern int rmr_bytes2meid(rmr_mbuf_t* mbuf, unsigned char const* src, int len); + Sets the managed entity field in the message and returns the number of bytes copied. + Refer to RMR C documentation for method:: + + extern int rmr_bytes2meid(rmr_mbuf_t* mbuf, unsigned char const* src, int len); Caution: the meid length supported in an RMR message is 32 bytes, but C applications expect this to be a nil terminated string and thus only 31 bytes are actually available. Raises: exceptions.MeidSizeOutOfRang + + Parameters + ---------- + ptr_mbuf: ctypes c_void_p + Pointer to an RMR message buffer + byte_tr: bytes + Managed entity ID value + + Returns + ------- + int: + number of bytes copied """ max = _get_constants().get("RMR_MAX_MEID", 32) if len(byte_str) >= max: @@ -421,19 +626,22 @@ _rmr_get_meid.argtypes = [POINTER(rmr_mbuf_t), c_char_p] _rmr_get_meid.restype = c_char_p -def rmr_get_meid(ptr_mbuf): +def rmr_get_meid(ptr_mbuf: POINTER(rmr_mbuf_t)) -> bytes: """ - Get the managed equipment ID (meid) from the message header. + Gets the managed entity ID (meid) from the message header. + This is a python-friendly version of RMR C method:: + + extern unsigned char* rmr_get_meid(rmr_mbuf_t* mbuf, unsigned char* dest); Parameters ---------- ptr_mbuf: ctypes c_void_p - Pointer to an rmr message buffer + Pointer to an RMR message buffer Returns ------- - string: - meid + bytes: + Managed entity ID """ sz = _get_constants().get("RMR_MAX_MEID", 32) # size for buffer to fill buf = create_string_buffer(sz) @@ -446,21 +654,35 @@ _rmr_get_src.argtypes = [POINTER(rmr_mbuf_t), c_char_p] _rmr_get_src.restype = c_char_p -def rmr_get_src(ptr_mbuf, dest): +def rmr_get_src(ptr_mbuf: POINTER(rmr_mbuf_t), dest: c_char_p) -> c_char_p: """ - Refer to the rmr C documentation for rmr_get_src - extern unsigned char* rmr_get_src(rmr_mbuf_t* mbuf, unsigned char* dest); + Copies the message-source information to the buffer. + Refer to RMR C documentation for method:: + + extern unsigned char* rmr_get_src(rmr_mbuf_t* mbuf, unsigned char* dest); + + Parameters + ---------- + ptr_mbuf: ctypes POINTER(rmr_mbuf_t) + Pointer to an RMR message buffer + dest: ctypes c_char_p + Pointer to a buffer to receive the message source + + Returns + ------- + string: + message-source information """ return _rmr_get_src(ptr_mbuf, dest) # Methods that exist ONLY in rmr-python, and are not wrapped methods -# In hindsight, I wish i put these in a seperate module, but leaving this here to prevent api breakage. +# In hindsight, I wish i put these in a separate module, but leaving this here to prevent api breakage. -def get_payload(ptr_mbuf): +def get_payload(ptr_mbuf: c_void_p) -> bytes: """ - Given a rmr_buf_t*, get it's binary payload as a bytes object + Gets the binary payload from the rmr_buf_t*. Parameters ---------- @@ -478,9 +700,9 @@ def get_payload(ptr_mbuf): return CharArr(*ptr_mbuf.contents.payload[:sz]).raw -def get_xaction(ptr_mbuf): +def get_xaction(ptr_mbuf: c_void_p) -> bytes: """ - given a rmr_buf_t*, get it's transaction id + Gets the transaction ID from the rmr_buf_t*. Parameters ---------- @@ -497,9 +719,9 @@ def get_xaction(ptr_mbuf): return val[:sz] -def message_summary(ptr_mbuf): +def message_summary(ptr_mbuf: c_void_p) -> dict: """ - Returns a dict that contains the fields of a message + Returns a dict with the fields of an RMR message. Parameters ---------- @@ -526,10 +748,9 @@ def message_summary(ptr_mbuf): } -def set_payload_and_length(byte_str, ptr_mbuf): +def set_payload_and_length(byte_str: bytes, ptr_mbuf: c_void_p): """ - | Set an rmr payload and content length - | In place method, no return + Sets an rmr payload and content length. Parameters ---------- @@ -537,6 +758,10 @@ def set_payload_and_length(byte_str, ptr_mbuf): the bytes to set the payload to ptr_mbuf: ctypes c_void_p Pointer to an rmr message buffer + + Returns + ------- + None """ if rmr_payload_size(ptr_mbuf) < len(byte_str): # existing message payload too small ptr_mbuf = rmr_realloc_payload(ptr_mbuf, len(byte_str), True) @@ -545,9 +770,9 @@ def set_payload_and_length(byte_str, ptr_mbuf): ptr_mbuf.contents.len = len(byte_str) -def generate_and_set_transaction_id(ptr_mbuf): +def generate_and_set_transaction_id(ptr_mbuf: c_void_p): """ - Generate a UUID and Set an rmr transaction id to it + Generates a UUID and sets the RMR transaction id to it Parameters ---------- @@ -557,9 +782,9 @@ def generate_and_set_transaction_id(ptr_mbuf): set_transaction_id(ptr_mbuf, uuid.uuid1().hex.encode("utf-8")) -def set_transaction_id(ptr_mbuf, tid_bytes): +def set_transaction_id(ptr_mbuf: c_void_p, tid_bytes: bytes): """ - Set an rmr transaction id + Sets an RMR transaction id TODO: on next API break, merge these two functions. Not done now to preserve API. Parameters @@ -573,9 +798,9 @@ def set_transaction_id(ptr_mbuf, tid_bytes): memmove(ptr_mbuf.contents.xaction, tid_bytes, sz) -def get_src(ptr_mbuf): +def get_src(ptr_mbuf: c_void_p) -> str: """ - Get the message source (likely host:port) + Gets the message source (likely host:port) Parameters ----------