hio.core.memo.memoing ===================== .. py:module:: hio.core.memo.memoing .. autoapi-nested-parse:: hio.core.memoing Module Mixin Base Classes that add support for memograms over datagram based transports. In this context, a memo made is a larger message that is partitioned into smaller memograms parts that fit into transport specific datagrams. This allows larger messages (memos) to be transported over datagram transports which messages are larger than a single datagram in the underlying transport. Module Contents --------------- .. py:class:: MemoGramCodex MemoGramCodex is codex of all varieties of MemoGram Hard Codes. Only provide defined codes. Undefined are left out so that inclusion(exclusion) via 'in' operator works. .. py:class:: ZeroGramCodex GramCodex is codex of all Zero Gram Hard Codes. Only provide defined codes. Undefined are left out so that inclusion(exclusion) via 'in' operator works. .. py:class:: GramCodex GramCodex is codex of all Non-Zero Gram Hard Codes. Only provide defined codes. Undefined are left out so that inclusion(exclusion) via 'in' operator works. .. py:class:: AuthGramCodex AuthGramCodex is codex of all AuthGram (authenticated signed) Hard Codes. Only provide defined codes. Undefined are left out so that inclusion(exclusion) via 'in' operator works. .. py:class:: AckCodex AckCodex is codex of all Ack Hard Codes. Only provide defined codes. Undefined are left out so that inclusion(exclusion) via 'in' operator works. .. py:class:: Memoer(*, tymeout=None, name=None, bc=None, bs=None, version=None, rxgs=None, sources=None, counts=None, vids=None, rxms=None, txms=None, txgs=None, txbs=None, code=MemoDex.GramZero, curt=False, size=None, authic=False, echoic=False, keep=None, vid=None, **kwa) Bases: :py:obj:`hio.base.tyming.Tymee` Memoer base class subclass of Tymee that adds memogram support to a transport class. Memoer supports memos composed of asynchronous memograms. Provides common methods for subclasses. A memogram is a higher level construct that sits on top of a datagram transport. A memogram supports the segmentation and desegmentation of memos to respect the underlying datagram size, buffer, and fragmentation behavior. When indicated a memoer provides reliable delivery over unreliable datagram transports using retry tymers and acknowldged services. Layering a reliable transaction protocol for memos on top of a memogram transport enables reliable asynchronous messaging over unreliable datagram transport protocols. When the datagram protocol is already reliable, then a memogram transport enables larger memos (messages) than that natively supported by the datagram. Usage:: Do not instantiate directly but use as a mixin with a transport class in order to create a new subclass that adds memogram support to the datagram transport class. For example MemoerUdp or MemoerUxd When using non-blocking IO, asynchronous datagram transport protocols may have hidden buffering constraints that result in fragmentation of the sent datagram which means the whole datagram is not sent at once via a non-blocking send call. This means that the remainder of the datagram must be sent later and may take multiple send calls to complete. The datagram protocol is responsible for managing the buffering and fragmentation but depends on the sender repeated attempts to send the remainder of the full datagram. This is ensured with the final tier with a raw transmit buffer that waits until it is empty before attempting to send another gram. Because sending to different destinations may fail for different reasons such as bad addresses or bad routing each destination gets its own buffer so that a bad destination does not block other destinations. Memo partition/departition information is embedded in the grams. When grams are signed, the signature is computed on the over the wire serialization of the header (qb2 or qb64). This is more efficient and since gram headers will be stripped and discarded there is no need to archive them. The encapsulated unpartitioned memogram with its signature it what is meant for archival not the partitioned gram and per gram signature. Each direction of dataflow uses a tiered set of buffers that respect the constraints of non-blocking asynchronous IO with datagram transports. Transmit Flow:: memo to .txms deque -> .rend -> grams to .txgs deque -> .send to .txbs On the transmit side memos are placed in a memo deque (double ended queue). Each memo is then segmented into grams (memograms) that respect the size constraints of the underlying datagram transport. These grams are placed in the outgoing gram deque. Each entry in this deque is a duple of form: (gram: bytes, dst: str). Each duple is pulled off the self._serviceOneRxMemo()deque and its gram is put in bytearray for transport. Receive Flow:: .receive -> (gram, src) -> grams parsed to .rxgs .counts .vids .sources -> signing key pair sigkey and verifier key -> .fuse -> memo .rxms deque On the receive side each complete memogram (gram) is put in a gram receive deque as a memogram (datagram sized) segment of a memo. These deques are indexed by the sender's source addr. The grams in the gram receive deque are then desegmented into a memo and placed in the memo deque for consumption by the application or some other higher level protocol. Inherited Class Attributes:: MaxGramSize (int): absolute max gram size on tx with overhead, override in subclass Class Attributes:: Version (Versionage): default version consisting of namedtuple of form (major: int, minor: int) Codex (GramDex): dataclass ref to gram codex Codes (dict): maps codex names to codex values Names (dict): maps codex values to codex names Sodex (SGDex): dataclass ref to signed gram codex Sizes (dict): gram head part sizes Sizage instances keyed by gram codes MaxMemoSize (int): absolute max memo size MaxGramCount (int): absolute max gram count BufSize (int): used to set default buffer size for transport datagram buffers Tymeout (float): default timeout for retry tymer(s) if any Stubbed Attributes:: name (str): unique name for Memoer transport. Used to manage multiple instances. opened (bool): True means transport open for use False otherwise bc (int or None): count of transport buffers of MaxGramSize bs (int or None): buffer size of transport buffers. When .bc is provided then .bs is calculated by multiplying, .bs = .bc * .MaxGramSize. When .bc is not provided, then if .bs is provided use provided value else use default .BufSize Stubbed Methods:: send(gram, dst, *, echoic=False) -> int # send gram over transport to dst receive(self, *, echoic=False) -> (bytes, str or tuple or None) # receive gram Attributes:: version (Versionage): version for this memoir instance consisting of namedtuple of form (major: int, minor: int) rxgs (dict): keyed by mid (memoID) with value of dict where each value dict holds grams from memo keyed by gram number. Grams have been stripped of their headers. The mid appears in every gram from the same memo. sources (dict): keyed by mid (memoID) that holds the src for the memo. This enables reattaching src to fused memo in rxms deque tuple. counts (dict): keyed by mid (memoID) that holds the gram count from the first gram for the memo. This enables lookup of the gram count when fusing its grams. vids (dict[mid: (vid or None)]): keyed by mid that holds the vid verifier ID str for the memo indexed by its mid (memoID). This enables reattaching the vid to memo when placing fused memo in rxms deque. vid is only present when signed header otherwise vid is None rxms (deque): holding rx (receive) memo tuples desegmented from rxgs grams each entry in deque is tuple of form: (memo: str, src: str, vid: str) where: memo is fused memo, src is source addr, vid is verifier ID txms (deque): holding tx (transmit) memo tuples to be segmented into txgs grams where each entry in deque is tuple of form (memo: str, dst: str, vid: str or None) memo is memo to be partitioned into gram dst is dst addr for grams vid is verifier id when gram is to be signed (authenticated) or None otherwise txgs (deque): grams to transmit, each entry is duple of form: (gram: bytes, dst: str). txbs (tuple): current transmisstion duple of form: (gram: bytearray, dst: str). gram bytearray may hold untransmitted portion when Encodesdatagram is not able to be sent all at once so can keep trying. Nothing to send indicated by (bytearray(), None) for (gram, dst) echos (deque): holds echo receive duples for testing. Each duple of form: (gram: bytes, dst: str). inbox (deque): holds final received complete memos for testing when not overridden in subclass to further process otherwise tymeout (float): default timeout for retry tymer(s) if any tymers (dict): keys are tid and values are Tymers for retry tymers for each inflight tx Inherited Properties (Tymee):: tyme (float or None): relative cycle time of associated Tymist which is provided by calling .tymth function wrapper closure which is obtained from Tymist.tymen(). None means not assigned yet. tymth (Callable or None): function wrapper closure returned by Tymist.tymen() method. When .tymth is called it returns associated Tymist.tyme. Provides injected dependency on Tymist cycle tyme base. None means not assigned yet. Properties:: code (bytes or None): gram code for gram header when rending for tx curt (bool): True means when rending for tx encode header in base2 False means when rending for tx encode header in base64 size (int): gram size when rending for tx. first gram size = over head size + neck size + body size. other gram size = over head size + body size. Min gram body size is one. Gram size also limited by MaxGramSize and MaxGramCount relative to MaxMemoSize. authic (bool): True means any rx grams must be signed. False otherwise echoic (bool): True means use .echos in .send and .receive to mock the transport layer for testing and debugging. False means do not use .echos. Each entry in .echos is a duple of form: (gram: bytes, src: str) Default echo is duple that indicates nothing to receive of form (b'', None). When False may be overridden by a method parameter. keep (dict): labels are vids, values are Keyage instances named tuple of signature key pair: sigkey = private signing key verkey = public verifying key Keyage = namedtuple("Keyage", "sigkey verkey") vid (str or None): own vid defaults used to lookup keys to sign on tx Hidden:: _code (bytes or None): see size property _curt (bool): see curt property _size (int): see size property _authic (bool): see authic property _echoic (bool): see echoic property _keep (dict): see keep property _oid (str or None): see vid property .. py:method:: makeMID(code='0A') :classmethod: Make new random memo ID (MID) as 24 char CESR encoded qb64 UUID Returns:: mid (str): 24 char qb64 CESR encoded qualified base64 from 128 bit UUID default CESR code '0A' labeled Salt_128 Parameters:: code (str): CESR code for MID .. py:property:: code Property getter for ._code Returns:: code (str): two char base64 gram code .. py:property:: curt Property getter for ._curt Returns:: curt (bool): True means when rending for tx encode header in base2 False means when rending for tx encode header in base64 .. py:property:: size Property getter for ._size, maximum gram size when rending for tx :returns: gram size when rending for tx. Zeroth gram size = zeroth overhead + body. Non-Zeroth gram size = non-zeroth overhead + body. Min gram body size is one. Gram size also limited by MaxGramSize and MaxGramCount relative to MaxMemoSize. :rtype: size (int) .. py:property:: vid Property getter for ._vid :returns: vid used to sign on tx if any :rtype: vid (str or None) .. py:property:: authic Property getter for ._authic :returns: True means any rx grams must be signed; False otherwise. :rtype: bool .. py:property:: echoic Property getter for ._echoic :returns: True means use .echos in .send and .receive to mock the transport layer for testing and debugging; False means do not use .echos. Each entry in .echos is a duple of form (gram: bytes, src: str). Default echo is a duple that indicates nothing to receive of form (b'', None). :rtype: bool .. py:property:: keep Property getter for ._keep :returns: Mapping of vids to Keyage instances (sigkey, verkey). :rtype: dict .. py:method:: open() Opens transport in nonblocking mode This is a stub. Override in transport specific subclass .. py:method:: reopen(**kwa) Idempotently open transport This is a stub. Override in transport specific subclass .. py:method:: close() Closes transport This is a stub. Override in transport subclass .. py:method:: wind(tymth) Inject new tymist.tymth as new ._tymth. Changes tymist.tyme base. Updates winds .tymer .tymth .. py:method:: serviceTymers() Service all retry tymers Must be overriden in subclass. This is a stub. .. py:method:: wiffOld(gram) Determines encoding of gram bytes header when parsing grams. The encoding maybe either base2 or base64. Returns:: curt (bool): True means base2 encoding False means base64 encoding Otherwise raises hioing.MemoerError All gram head codes start with '_' in base64 text or in base2 binary. Given only allowed chars are from the set of base64 then can determine if header is in base64 or base2. First sextet: (0b is binary, 0o is octal, 0x is hexadecimal) 0o27 = 0b010111 means first sextet of '_' in base64 0o77 = 0b111111 means first sextet of '_' in base2 Assuming that only '_' is allowed as the first char of a valid gram head, in either Base64 or Base2 encoding, a parser can unambiguously determine if the gram header encoding is binary Base2 or text Base64 because 0o27 != 0o77. Furthermore, it just so happens that 0o27 is a unique first sextet among Base64 ascii chars. So an invalid gram header when in Base64 encoding is detectable. However, there is one collision (see below) with invalid gram headers in Base2 encoding. So an erroneously constructed gram might not be detected merely by looking at the first sextet. Therefore unreliable transports must provide some additional mechanism such as a hash or signature on the gram. All Base2 codes for Base64 chars are unique since the B2 codes are just the count from 0 to 63. There is one collision, however, between Base2 and Base 64 for invalid gram headers. This is because 0o27 is the base2 code for ascii 'X'. This means that Base2 encodings that begin with 0o27 which is the Base2 encoding of the ascii 'X', would be incorrectly detected as text not binary. .. py:method:: wiff(gram) Determines encoding of gram bytes header when parsing grams. The encoding maybe either base2 or base64. Returns:: curt (bool): True means base2 encoding False means base64 encoding Otherwise raises hioing.MemoerError All gram head codes start with '1' in base64 text or in base2 binary. Given only allowed chars are from the set of base64 then can determine if header is in base64 or base2. 1AAQ, 1AAR, 1AAS, 1AAT, 1AAU, 1AAV, 1AAW, 1AAX, 1AAY, 1AAZ First sextet: 0b is binary, 0o is octal 2 octal digits or 6 bits 0x is hexadecimal 1 sextet is 1.5 hex digits or octets 0o14 = 0b001100 means first sextet of '1' in base64 (0b00110001) 0o65 = 0b110101 means first sextet of '1' in base2 (0b110101) Assuming that only '1' is allowed as the first char of a valid gram head, in either Base64 or Base2 encoding, a parser can unambiguously determine if the gram header encoding is binary Base2 or text Base64 because 0o14 != 0o65. The sextet 0o14 is not a unique first sextet among Base64 ascii chars. It is shared with the ascii chars '0', '1', '2', '3'. So an invalidly encoded gram header when in Base64 encoding is not fully detectable unless the full first octet (8bits) is examined. But an invalid gram header could have any of the following sextets also encoded invalidly. Thise means that in general some other mechanism is required to detect and invalidly encoded gram header. Therefore some additional tamper evident mechanism such as a digest or signature is required to detect and invalidly encoded gram header. But all we really need wiff to do is to detect if a validly encoded gram header is encoded in Base64 or Base2 and merely examining the first sextet is enough to unambiguously make that determination. In addition there is one collision (see below) with invalid gram headers in Base2 encoding. So an erroneously constructed gram might not be detected merely by looking at the first sextet. All Base2 codes for Base64 chars are unique since the B2 codes are just the count from 0 to 63. There is one collision, however, between Base2 and Base 64 for the first sextet of an invalid gram header. This is because 0o14 is the base2 code for ascii 'M'. This means that invalid Base2 encoded gram headers that begin with 0o14 (the Base2 encoding of the ascii 'M') would be incorrectly detected by wiff as text not binary. .. py:method:: verify(vid, sig, ser) Verify signature sig on signed part of gram, ser, using current verkey for vid. Verify the signature on the header as per the serialized header format given by the header code as either qb2 or qb64. Do not convert qb2 to qb64 or vice versa. Allowed Codes: (CESR compatible) Ed25519_Sig: str = '0B' # Ed25519 signature. not indexed :returns: True if signature verifies Raises MemoerVerifyError otherwise :rtype: result (bool) :param vid: qualified base64 qb64b of verifier ID :type vid: bytes or str :param sig: qualified base64 qb64b signature :type sig: bytes or str :param ser: serialization to be signed :type ser: bytes or str .. py:method:: pick(gram) Strips header from gram bytearray leaving only gram body in gram and returns (mid, gn, gc). Raises MemoerError if unrecognized or invalid header this includes signature verification failure when signed. When signed the signature is computed on the body of the gram as is when gramified for transmission whether the body be in domain qb64b or qb2. The body is assumed to always be in the raw domain ser when signed. The header and signature parts are converted to raw from base2 or base64 Note the full packet itself is not concatenation composable (does not align on 24 bit boundary) as per CESR. Only the header elements and sig are CESR 24 bit aligned so there is no enmass conversion possible of concatenated memograms. This is ok for a datagram segmentation that is decidedly not a stream. :returns: tuple of form: (mid: str, vid: str, gn: int, gc: int or None) where: mid is fully qualified memoID, vid is verifier ID used to look up signature verification key, gn is gram number, gc is gram count. When first gram (zeroth) returns (mid, vid, 0, gc). When other gram returns (mid, vid, gn, None) When code has empty vid then vid is None Otherwise raises MemoerError error. :rtype: result (tuple) When valid recognized header, strips header bytes from front of gram leaving the gram body part bytearray. :param gram: memo gram from which to parse and strip its header. :type gram: bytearray .. py:method:: pickOld(gram) Strips header from gram bytearray leaving only gram body in gram and returns (mid, gn, gc). Raises MemoerError if unrecognized or invalid header this includes signature verification failure when signed. When signed the signature is computed on the domain qb64b or qb2 that the packet is transmitted in. Note the packet itself is not concatenation composable as per CESR only the header elements and sig are CESR 24 bit aligned so there is no enmass conversion of concatenated memograms. This is ok for a datagram segmentation that is decidedly not a stream. :returns: tuple of form: (mid: str, vid: str, gn: int, gc: int or None) where: mid is fully qualified memoID, vid is verifier ID used to look up signature verification key, gn is gram number, gc is gram count. When first gram (zeroth) returns (mid, vid, 0, gc). When other gram returns (mid, vid, gn, None) When code has empty vid then vid is None Otherwise raises MemoerError error. :rtype: result (tuple) When valid recognized header, strips header bytes from front of gram leaving the gram body part bytearray. :param gram: memo gram from which to parse and strip its header. :type gram: bytearray .. py:method:: receive(*, echoic=False) -> (bytes, str or tuple or None) Attempts to receive bytes from remote source. May use echoic=True and .echos to mock a transport layer for testing Puts sent gram into .echos so that .receive can extract it when using same Memoer to send and receive to itself via its own .echos When using different Memoers each for send and receive then must manually copy from sender Memoer .echos to Receiver Memoer .echos Must be overridden in subclass. This is a stub to define mixin interface. :param echoic: True means use .echos in .send and .receive to mock the transport layer for testing and debugging; False means do not use .echos. Each entry in .echos is a duple of form (gram: bytes, src: str). Default echo is a duple that indicates nothing to receive of form (b'', None). :type echoic: bool :returns: (data: bytes, src: str or tuple or None) where data is the bytes of received data and src is the source address. When no data the duple is (b'', None) unless echoic is True, then pop off echo from .echos. :rtype: tuple .. py:method:: serviceReceivesOnce(*, echoic=False) Service receives once (non-greedy) and queue up :param echoic: True means use .echos in .receive debugging purposes where echo is duple of form: (gram: bytes, src: str) False means do not use .echos default is duple that indicates nothing to receive of form (b'', None) :type echoic: bool .. py:method:: serviceReceives(*, echoic=False) Service all receives (greedy) and queue up :param echoic: True means use .echos in .receive debugging purposes where echo is duple of form: (gram: bytes, src: str) False means do not use .echos default is duple that indicates nothing to receive of form (b'', None) :type echoic: bool .. py:method:: fuse(grams, cnt) Fuse cnt gram body parts from grams dict into whole memo . If any grams are missing then returns None. :returns: fused memo or None if incomplete. :rtype: memo (str or None) Override in subclass :param grams: memo gram body parts each keyed by gram number from which to fuse memo. Headers have been stripped. :type grams: dict :param cnt: gram count for mid :type cnt: int .. py:method:: serviceRxGramsOnce() Service one pass (non-greedy) over all unique sources in .rxgs dict if any for received incoming grams. .. py:method:: serviceRxGrams() Service one pass (non-greedy) over all unique sources in .rxgs dict if any for received incoming grams. No different from serviceRxGramsOnce because service all mids each pass. .. py:method:: serviceRxMemosOnce() Service memos in .rxms deque once (non-greedy one memo) if any Override in subclass to handle result and put it somewhere .. py:method:: serviceRxMemos() Service all memos in .rxms (greedy) if any Override in subclass to handle result(s) and put them somewhere .. py:method:: serviceAllRxOnce() Service receive side of stack once (non-greedy) .. py:method:: serviceAllRx() Service receive side of stack (greedy) until empty or waiting for more .. py:method:: memoit(memo, dst, vid=None) Append (memo, dst, vid) tuple to .txms deque :param memo: to be segmented and packed into gram(s) :type memo: str :param dst: address of remote destination of memo :type dst: str :param vid: verifier ID for verifying signature on grams :type vid: str or None .. py:method:: sign(vid, ser) Sign serialization ser using private sigkey for verifier ID vid and return signature in serialized format defined by .curt Sign the serialized signed part of gram given by ser. Assumes that the header in ser is in qb2 or qb64 as defined by .curt Allowed Codes for sigseed: Ed25519_Seed:str = 'A' # Ed25519 256 bit random seed for private key :returns: qb64b or qb2 when .curt if not .curt then qualified base64 of signature else if .curt then qualified base2 of signature raises MemoerError if problem signing :rtype: sig (bytes) :param vid: qb64 or qb2 if .curt of vid of signer assumes vid of correct length :type vid: bytes or str :param ser: serialization to be signed (usually qb64 or qb64b) :type ser: bytes or str .. py:method:: rend(memo, vid=None) Partition memo into packed grams with headers. :returns: list of grams with headers. :rtype: grams (list[bytes]) :param memo: to be partitioned into grams with headers :type memo: str :param vid: verifier ID when gram is to be signed, used to lookup sigkey to sign. None means not signable :type vid: str or None Note zeroth gram has head + neck overhead, zhz = oz + nz so bz that fits is smaller by nz relative to non-zeroth non-zeroth grams just head overhead oz so bz that fits is bigger by nz relative to zeroth .. py:method:: send(gram, dst, *, echoic=False) -> int Attempts to send bytes in txbs to remote destination dst. May use echoic=True and .echos to mock a transport layer for testing Puts sent gram into .echos so that .receive can extract it when using same Memoer to send and receive to itself via its own .echos When using different Memoers each for send and receive then must manually copy from sender Memoer .echos to Receiver Memoer .echos Must be overridden in subclass. This is a stub to define mixin interface. :returns: bytes actually sent :rtype: count (int) :param gram: of bytes to send :type gram: bytearray :param dst: remote destination address :type dst: str :param echoic: True means use .echos in .send and .receive to mock the transport layer for testing and debugging; False means do not use .echos. Each entry in .echos is a duple of form (gram: bytes, src: str). Default echo is a duple that indicates nothing to receive of form (b'', None). :type echoic: bool .. py:method:: serviceTxMemosOnce() Service one outgoing memo from .txms deque if any (non-greedy) .. py:method:: serviceTxMemos() Service all outgoing memos in .txms deque if any (greedy) .. py:method:: gramit(gram, dst) Append (gram, dst) duple to .txgs deque. Utility method for testing. :param gram: gram to be sent :type gram: bytes :param dst: address of remote destination of gram :type dst: str .. py:method:: serviceTxGramsOnce(*, echoic=False) Service one pass (non-greedy) over all unique destinations in .txgs dict if any for blocked destination or unblocked with pending outgoing grams. :param echoic: True means echo sends into receives via. echos False measn do not echo :type echoic: bool .. py:method:: serviceTxGrams(*, echoic=False) Service multiple passes (greedy) over all unqique destinations in .txgs dict if any for blocked destinations or unblocked with pending outgoing grams until there is no unblocked destination with a pending gram. :param echoic: True means echo sends into receives via. echos False measn do not echo :type echoic: bool .. py:method:: serviceAllTxOnce() Service the transmit side once (non-greedy) one transmission. .. py:method:: serviceAllTx() Service the transmit side until empty (greedy) multiple transmissions until blocked by pending transmission on transport. .. py:method:: serviceLocal() Service the local Peer's receive and transmit queues .. py:method:: serviceAllOnce() Service all Rx and Tx Once (non-greedy) .. py:method:: serviceAll() Service all Rx and Tx (greedy) .. py:function:: openMemoer(cls=None, name='test', **kwa) Wrapper to create and open Memoer instances When used in with statement block, calls .close() on exit of with block :param cls: instance of subclass instance :type cls: Class :param name: unique identifier of Memoer peer. Enables management of transport by name. :type name: str Usage:: with openMemoer() as peer: peer.receive() with openMemoer(cls=MemoerSub) as peer: peer.receive() .. py:class:: MemoerDoer(peer, **kwa) Bases: :py:obj:`hio.base.doing.Doer` Memoer Doer for both reliable and unreliable transports. Doer is a subclass of Tymee and is wound. Reliable do not require retry tymers Unreliable require retry tymers for acknowldged services. See Doer for inherited attributes, properties, and methods. Attributes:: .peer (Memoer): underlying transport instance subclass of Memoer .. py:method:: wind(tymth) Inject new tymist.tymth as new ._tymth. Changes tymist.tyme base. Updates winds .tymer .tymth .. py:method:: enter(*, temp=None) Do 'enter' context actions. Override in subclass. Not a generator method. Set up resources. Comparable to context manager enter. :param temp: True means use temporary file resources if any None means ignore parameter value. Use self.temp :type temp: bool or None Inject temp or self.temp into file resources here if any Doist or DoDoer winds its doers on enter .. py:method:: recur(tyme) Run one service cycle for the peer. .. py:method:: exit() Do 'exit' context actions. Override in subclass. Not a generator method. Clean up resources. Comparable to context manager exit. Called by finally after normal return, close, or abort. After .exit() do returns resulting in StopIteration. .. py:class:: AuthMemoer(*, code=MemoDex.GramAuthZero, authic=True, **kwa) Bases: :py:obj:`Memoer` AuthMemoer mixin base class that enforces authenticated memo delivery. Subclass of Tymee and Memoer Inherited Class Attributes (Memoer):: Version (Versionage): default version consisting of namedtuple of form (major: int, minor: int) Codex (GramDex): dataclass ref to gram codex Codes (dict): maps codex names to codex values Names (dict): maps codex values to codex names Sodex (SGDex): dataclass ref to signed gram codex Sizes (dict): gram head part sizes Sizage instances keyed by gram codes MaxMemoSize (int): absolute max memo size MaxGramCount (int): absolute max gram count BufSize (int): used to set default buffer size for transport datagram buffers Tymeout (float): default timeout for retry tymer(s) if any Inherited Stubbed Attributes (Memoer):: name (str): unique name for Memoer transport. Used to manage multiple instances. opened (bool): True means transport open for use False otherwise bc (int or None): count of transport buffers of MaxGramSize bs (int or None): buffer size of transport buffers. When .bc is provided then .bs is calculated by multiplying, .bs = .bc * .MaxGramSize. When .bc is not provided, then if .bs is provided use provided value else use default .BufSize Inherited Stubbed Methods (Memoer):: send(gram, dst, *, echoic=False) -> int # send gram over transport to dst receive(self, *, echoic=False) -> (bytes, str or tuple or None) # receive gram Inherited Attributes (Memoer):: version (Versionage): version for this memoir instance consisting of namedtuple of form (major: int, minor: int) rxgs (dict): keyed by mid (memoID) with value of dict where each value dict holds grams from memo keyed by gram number. Grams have been stripped of their headers. The mid appears in every gram from the same memo. sources (dict): keyed by mid (memoID) that holds the src for the memo. This enables reattaching src to fused memo in rxms deque tuple. counts (dict): keyed by mid (memoID) that holds the gram count from the first gram for the memo. This enables lookup of the gram count when fusing its grams. vids (dict[mid: (vid or None)]): keyed by mid that holds the verifier ID str for the memo indexed by its mid (memoID). This enables reattaching the vid to memo when placing fused memo in rxms deque. Vid is only present when signed header otherwise vid is None rxms (deque): holding rx (receive) memo tuples desegmented from rxgs grams each entry in deque is tuple of form: (memo: str, src: str, vid: str) where: memo is fused memo, src is source addr, vid is verifier ID txms (deque): holding tx (transmit) memo tuples to be segmented into txgs grams where each entry in deque is tuple of form (memo: str, dst: str, vid: str or None) memo is memo to be partitioned into gram dst is dst addr for grams vid is verifier id when gram is to be signed or None otherwise txgs (deque): grams to transmit, each entry is duple of form: (gram: bytes, dst: str). txbs (tuple): current transmisstion duple of form: (gram: bytearray, dst: str). gram bytearray may hold untransmitted portion when Encodesdatagram is not able to be sent all at once so can keep trying. Nothing to send indicated by (bytearray(), None) for (gram, dst) echos (deque): holding echo receive duples for testing. Each duple of form: (gram: bytes, dst: str). tymeout (float): default timeout for retry tymer(s) if any tymers (dict): keys are tid and values are Tymers for retry tymers for each inflight tx Inherited Properties (Tymee):: tyme (float or None): relative cycle time of associated Tymist which is provided by calling .tymth function wrapper closure which is obtained from Tymist.tymen(). None means not assigned yet. tymth (Callable or None): function wrapper closure returned by Tymist.tymen() method. When .tymth is called it returns associated Tymist.tyme. Provides injected dependency on Tymist cycle tyme base. None means not assigned yet. Inherited Properties (Memoer):: code (bytes or None): gram code for gram header when rending for tx curt (bool): True means when rending for tx encode header in base2 False means when rending for tx encode header in base64 size (int): gram size when rending for tx. first gram size = over head size + neck size + body size. other gram size = over head size + body size. Min gram body size is one. Gram size also limited by MaxGramSize and MaxGramCount relative to MaxMemoSize. authic (bool): True means any rx grams must be signed. False otherwise echoic (bool): True means use .echos in .send and .receive to mock the transport layer for testing and debugging. False means do not use .echos Each entry in .echos is a duple of form: (gram: bytes, src: str) Default echo is duple that indicates nothing to receive of form (b'', None) When False may be overridden by a method parameter keep (dict): labels are vids, values are Keyage instances named tuple of signature key pair: sigkey = private signing key verkey = public verifying key Keyage = namedtuple("Keyage", "sigkey verkey") vid (str or None): own vid defaults used to lookup keys to sign on tx .. py:function:: openAM(cls=None, name='test', **kwa) Wrapper to create and open SureMemoer instances When used in with statement block, calls .close() on exit of with block :param cls: instance of subclass instance :type cls: Class :param name: unique identifier of Memoer peer. Enables management of transport by name. :type name: str Usage:: with openAM() as peer: peer.receive() with openAM(cls=SureMemoerSub) as peer: peer.receive() .. py:class:: AuthMemoerDoer(peer, **kwa) Bases: :py:obj:`hio.base.doing.Doer` AuthMemoerDoer Doer to ensure authenticated/signed memograms. For both reliable and unreliable transports. Reliable do not require retry tymers Unreliable require retry tymers for acknowldged services. See Doer for inherited attributes, properties, and methods. Doer is a subclass of Tymee and is wound. Attributes:: .peer (AuthMemoer) is underlying transport instance subclass of AuthMemoer .. py:method:: wind(tymth) Inject new tymist.tymth as new ._tymth. Changes tymist.tyme base. Updates winds .tymer .tymth .. py:method:: enter(*, temp=None) Do 'enter' context actions. Override in subclass. Not a generator method. Set up resources. Comparable to context manager enter. :param temp: True means use temporary file resources if any None means ignore parameter value. Use self.temp :type temp: bool or None Inject temp or self.temp into file resources here if any Doist or DoDoer winds its doers on enter .. py:method:: recur(tyme) Run one service cycle for the peer. .. py:method:: exit() Do 'exit' context actions. Override in subclass. Not a generator method. Clean up resources. Comparable to context manager exit. Called by finally after normal return, close, or abort. After .exit() do returns resulting in StopIteration.