Switch to SI95.
[ric-plt/lib/rmr.git] / src / bindings / rmr-python / rmr / rmr.py
index 0265e21..413d8dc 100644 (file)
@@ -1,6 +1,7 @@
+# vim: expandtab ts=4 sw=4:
 # ==================================================================================
 # ==================================================================================
-#       Copyright (c) 2019 Nokia
-#       Copyright (c) 2018-2019 AT&T Intellectual Property.
+#       Copyright (c) 2019-2020 Nokia
+#       Copyright (c) 2018-2020 AT&T Intellectual Property.
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -19,15 +20,14 @@ 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 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 rmr.exceptions import BadBufferAllocation
+from 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
 
 # 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
-_ = CDLL("libnng.so", mode=RTLD_GLOBAL)
-rmr_c_lib = CDLL("librmr_nng.so", mode=RTLD_GLOBAL)
+rmr_c_lib = CDLL("librmr_si.so", mode=RTLD_GLOBAL)
 
 
 # Internal Helpers (not a part of public api)
 
 
 # Internal Helpers (not a part of public api)
@@ -168,8 +168,14 @@ def rmr_init(uproto_port, max_msg_size, flags):
     """
     Refer to rmr C documentation for rmr_init
     extern void* rmr_init(char* uproto_port, int max_msg_size, int flags)
     """
     Refer to rmr C documentation for rmr_init
     extern void* rmr_init(char* uproto_port, int max_msg_size, int flags)
+
+    This python function checks that the context is not None and raises
+    an excption if it is.
     """
     """
-    return _rmr_init(uproto_port, max_msg_size, flags)
+    mrc = _rmr_init(uproto_port, max_msg_size, flags)
+    if mrc is None:
+        raise InitFailed()
+    return mrc
 
 
 _rmr_ready = rmr_c_lib.rmr_ready
 
 
 _rmr_ready = rmr_c_lib.rmr_ready
@@ -215,25 +221,34 @@ _rmr_alloc_msg.argtypes = [c_void_p, c_int]
 _rmr_alloc_msg.restype = POINTER(rmr_mbuf_t)
 
 
 _rmr_alloc_msg.restype = POINTER(rmr_mbuf_t)
 
 
-def rmr_alloc_msg(vctx, size, payload=None, gen_transaction_id=False, mtype=None, meid=None):
+def rmr_alloc_msg(
+    vctx, size, 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)
     """
     Refer to the rmr C documentation for rmr_alloc_msg
     extern rmr_mbuf_t* rmr_alloc_msg(void* vctx, int size)
+    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 payload is not None, attempts to set the payload
-    if gen_transaction_id is True, it generates and sets a transaction id
+    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 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
 
     """
     sbuf = _rmr_alloc_msg(vctx, size)
 
     """
     sbuf = _rmr_alloc_msg(vctx, size)
-    # make sure it's good
     try:
     try:
+        # make sure the alloc worked
         sbuf.contents
         sbuf.contents
+
+        # set specified fields
         if payload:
             set_payload_and_length(payload, sbuf)
 
         if payload:
             set_payload_and_length(payload, sbuf)
 
-        if gen_transaction_id:
+        if fixed_transaction_id:
+            set_transaction_id(sbuf, fixed_transaction_id)
+        elif gen_transaction_id:
             generate_and_set_transaction_id(sbuf)
 
         if mtype:
             generate_and_set_transaction_id(sbuf)
 
         if mtype:
@@ -242,12 +257,28 @@ def rmr_alloc_msg(vctx, size, payload=None, gen_transaction_id=False, mtype=None
         if meid:
             rmr_set_meid(sbuf, meid)
 
         if meid:
             rmr_set_meid(sbuf, meid)
 
+        if sub_id:
+            sbuf.contents.sub_id = sub_id
+
         return sbuf
 
     except ValueError:
         raise BadBufferAllocation
 
 
         return sbuf
 
     except ValueError:
         raise BadBufferAllocation
 
 
+_rmr_realloc_payload = rmr_c_lib.rmr_realloc_payload
+_rmr_realloc_payload.argtypes = [POINTER(rmr_mbuf_t), c_int, c_int, c_int]  # new_len, copy, clone
+_rmr_realloc_payload.restype = POINTER(rmr_mbuf_t)
+
+
+def rmr_realloc_payload(ptr_mbuf, new_len, 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)
+    """
+    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.restype = None
 _rmr_free_msg = rmr_c_lib.rmr_free_msg
 _rmr_free_msg.argtypes = [c_void_p]
 _rmr_free_msg.restype = None
@@ -256,7 +287,7 @@ _rmr_free_msg.restype = None
 def rmr_free_msg(mbuf):
     """
     Refer to the rmr C documentation for rmr_free_msg
 def rmr_free_msg(mbuf):
     """
     Refer to the rmr C documentation for rmr_free_msg
-    extern void rmr_free_msg( rmr_mbuf_t* mbuf )
+    extern void rmr_free_msg(rmr_mbuf_t* mbuf )
     """
     if mbuf is not None:
         _rmr_free_msg(mbuf)
     """
     if mbuf is not None:
         _rmr_free_msg(mbuf)
@@ -324,11 +355,22 @@ _rmr_rts_msg.argtypes = [c_void_p, POINTER(rmr_mbuf_t)]
 _rmr_rts_msg.restype = POINTER(rmr_mbuf_t)
 
 
 _rmr_rts_msg.restype = POINTER(rmr_mbuf_t)
 
 
-def rmr_rts_msg(vctx, ptr_mbuf):
+def rmr_rts_msg(vctx, ptr_mbuf, payload=None, mtype=None):
     """
     Refer to the rmr C documentation for rmr_rts_msg
     extern rmr_mbuf_t*  rmr_rts_msg(void* vctx, rmr_mbuf_t* msg)
     """
     Refer to the rmr C documentation for rmr_rts_msg
     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
     """
     """
+
+    if payload:
+        set_payload_and_length(payload, ptr_mbuf)
+
+    if mtype:
+        ptr_mbuf.contents.mtype = mtype
+
     return _rmr_rts_msg(vctx, ptr_mbuf)
 
 
     return _rmr_rts_msg(vctx, ptr_mbuf)
 
 
@@ -354,7 +396,16 @@ def rmr_set_meid(ptr_mbuf, byte_str):
     """
     Refer to the rmr C documentation for rmr_bytes2meid
     extern int rmr_bytes2meid(rmr_mbuf_t* mbuf, unsigned char const* src, int len);
     """
     Refer to the rmr C documentation for rmr_bytes2meid
     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
     """
     """
+    max = _get_constants().get("RMR_MAX_MEID", 32)
+    if len(byte_str) >= max:
+        raise MeidSizeOutOfRange
+
     return _rmr_bytes2meid(ptr_mbuf, byte_str, len(byte_str))
 
 
     return _rmr_bytes2meid(ptr_mbuf, byte_str, len(byte_str))
 
 
@@ -384,7 +435,7 @@ def rmr_get_meid(ptr_mbuf):
     string:
         meid
     """
     string:
         meid
     """
-    sz = _get_constants().get("RMR_MAX_MEID", 64)  # size for buffer to fill
+    sz = _get_constants().get("RMR_MAX_MEID", 32)  # size for buffer to fill
     buf = create_string_buffer(sz)
     _rmr_get_meid(ptr_mbuf, buf)
     return buf.value
     buf = create_string_buffer(sz)
     _rmr_get_meid(ptr_mbuf, buf)
     return buf.value
@@ -487,23 +538,39 @@ def set_payload_and_length(byte_str, ptr_mbuf):
     ptr_mbuf: ctypes c_void_p
         Pointer to an rmr message buffer
     """
     ptr_mbuf: ctypes c_void_p
         Pointer to an rmr message buffer
     """
+    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)
+
     memmove(ptr_mbuf.contents.payload, byte_str, len(byte_str))
     ptr_mbuf.contents.len = len(byte_str)
 
 
 def generate_and_set_transaction_id(ptr_mbuf):
     """
     memmove(ptr_mbuf.contents.payload, byte_str, len(byte_str))
     ptr_mbuf.contents.len = len(byte_str)
 
 
 def generate_and_set_transaction_id(ptr_mbuf):
     """
-    | Generate a UUID and Set an rmr transaction id to it
-    | In place method, no return
+    Generate a UUID and Set an rmr transaction id to it
+
+    Parameters
+    ----------
+    ptr_mbuf: ctypes c_void_p
+        Pointer to an rmr message buffer
+    """
+    set_transaction_id(ptr_mbuf, uuid.uuid1().hex.encode("utf-8"))
+
+
+def set_transaction_id(ptr_mbuf, tid_bytes):
+    """
+    Set an rmr transaction id
+    TODO: on next API break, merge these two functions. Not done now to preserve API.
 
     Parameters
     ----------
     ptr_mbuf: ctypes c_void_p
         Pointer to an rmr message buffer
 
     Parameters
     ----------
     ptr_mbuf: ctypes c_void_p
         Pointer to an rmr message buffer
+    tid_bytes: bytes
+        bytes of the desired transaction id
     """
     """
-    uu_id = uuid.uuid1().hex.encode("utf-8")
     sz = _get_constants().get("RMR_MAX_XID", 0)
     sz = _get_constants().get("RMR_MAX_XID", 0)
-    memmove(ptr_mbuf.contents.xaction, uu_id, sz)
+    memmove(ptr_mbuf.contents.xaction, tid_bytes, sz)
 
 
 def get_src(ptr_mbuf):
 
 
 def get_src(ptr_mbuf):