<commit_before>#  Copyright (c) 2001 Autonomous Zone Industries
#  This file is licensed under the
#    GNU Lesser General Public License v2.1.
#    See the file COPYING or visit http://www.gnu.org/ for details.

__revision__ = "$Id: Conversation.py,v 1.12 2003/02/02 19:31:37 myers_carpenter Exp $"

# Python standard library modules
import threading
import types
import traceback
import sys
from sha import sha
from time import time
import exceptions
import socket
import os
import types
from traceback import print_exc

# pyutil modules
from pyutil.debugprint import debugprint, debugstream
from pyutil import Cache
from pyutil import DoQ, nummedobj

# EGTP modules
from egtp import CommStrat
from egtp.CommHints import HINT_EXPECT_RESPONSE, HINT_EXPECT_MORE_TRANSACTIONS, HINT_EXPECT_NO_MORE_COMMS, HINT_EXPECT_TO_RESPOND, HINT_THIS_IS_A_RESPONSE, HINT_NO_HINT
from egtp import MojoMessage
from egtp import humanreadable, idlib, mencode, mojosixbit, std
from egtp.MojoHandicapper import DISQUALIFIED
from egtp.crypto import modval
from egtp.crypto import randsource

true = 1
false = 0

HANDLED = 0
EXPECTING_RESPONSE = 1

TUNING_FACTOR=float(2**8)

def is_mojo_message(thingie):
    return (type(thingie) is types.DictType) and (thingie.has_key('mojo header') or thingie.has_key('mojo message'))

class DebugDiagLoop(DoQ.DoQLoop, nummedobj.NummedObj):
    def __init__(self, cm):
        self.maxcbs = 0
        self.maxpcbs = 0
        self.maxoms = 0
        self.maxli2i = 0
        self.maxfps = 0
        DoQ.DoQLoop.__init__(self)
        nummedobj.NummedObj.__init__(self)
        self.cm = cm
        self.schedule_event()

    def event(self):
        if len(self.cm._callback_functions) > self.maxcbs:
            self.maxcbs = len(self.cm._callback_functions)
            debugprint("%s.event(): new max len(self.cm._callback_functions): %s, len(self.cm._posttimeout_callback_functions): %s, len(self.cm._map_inmsgid_to_info): %s, len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        if len(self.cm._posttimeout_callback_functions) > self.maxpcbs:
            self.maxpcbs = len(self.cm._posttimeout_callback_functions)
            debugprint("%s.event(): len(self.cm._callback_functions): %s, new max len(self.cm._posttimeout_callback_functions): %s, len(self.cm._map_inmsgid_to_info): %s, len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        if len(self.cm._callback_functions) > self.maxoms:
            self.maxoms = len(self.cm._callback_functions)
            debugprint("%s.event(): len(self.cm._callback_functions): %s, len(self.cm._posttimeout_callback_functions): %s, new max len(self.cm._callback_functions): %s, len(self.cm._map_inmsgid_to_info): %s, len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        if len(self.cm._map_inmsgid_to_info) > self.maxli2i:
            self.maxli2i = len(self.cm._map_inmsgid_to_info)
            debugprint("%s.event(): len(self.cm._callback_functions): %s, len(self.cm._posttimeout_callback_functions): %s, new max len(self.cm._map_inmsgid_to_info): %s, len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        if len(self.cm._map_cid_to_freshness_proof) > self.maxfps:
            self.maxfps = len(self.cm._map_cid_to_freshness_proof)
            debugprint("%s.event(): len(self.cm._callback_functions): %s, len(self.cm._posttimeout_callback_functions): %s, len(self.cm._map_inmsgid_to_info): %s, new max len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        self.schedule_event(delay=60)

class ConversationManager:
    def __init__(self, MTM):
        self._MTM = MTM
        # maps first message ids to (counterparty_id, callback function, notes for callback, conversation type, post_timeout_callback_func, timeoutcheckerschedtime,)
        self.__callback_functions = {}

        # maps message id's of messages who's responses have timed out to (recipient_id, conversation type, time of timeout, post timeout callback function, notes [only if post timeout callback function])
        # Reminder: this indirectly holds references to the original outgoing message body as well as the metainfo used to send it.  That is often large.
        self.__posttimeout_callback_functions = Cache.LRUCache(maxsize=512)

        # maps message id to (binary counterparty_id, message type, response status)
        # where status is HANDLED or EXPECTING_RESPONSE
        # This data structure is used between receiving a specific initiating message and
        # sending the response to it.  It is not used for incoming response messages.
        self._map_inmsgid_to_info = {}

        # This is a map from counterparty_id to the binary msgId of the last message you
        # received from that counterparty.  We use the msgId in outgoing messages, thus proving
        # to the counterparty that our messages are fresh (i.e., they are not replay attacks or
        # other sneaky trickery).  Actually our current software does not check the incoming
        # freshness proofs, but this code ensures that when we ship a new, replay-attack-proof
        # version which _does_ verify freshness proofs, then older apps which are running _this_
        # version of our software will be able to interoperate with it.
        self._map_cid_to_freshness_proof = Cache.LRUCache(maxsize=512)

        self._in_message_num = 0L   # used only in debugging

        if DEBUG_MODE:
            DebugDiagLoop(self) # this will spew a debug diags line every 60 seconds

    def shutdown(self):
        debugprint("self._map_inmsgid_to_info: %s\n", args=(self._map_inmsgid_to_info,), v=6, vs="debug")
        self.__callback_functions = {}
        # TODO: del this No other ref to this --icepick 2002-02-01
        # self._posttimeout_callback_functions.clear()
        self._map_inmsgid_to_info = {}
        self._map_cid_to_freshness_proof.clear()
        if hasattr(self, '_MTM'):
            del self._MTM  # break our circular reference

    def initiate_and_return_first_message(self, counterparty_id, conversationtype, firstmsgbody, outcome_func, timeout = 300, notes = None, mymetainfo=None, post_timeout_outcome_func=None):
        """
        @precondition: `counterparty_id' must be  an id.: idlib.is_sloppy_id(counterparty_id): "id: %s" % humanreadable.hr(id)

        @return: a tuple of (message_id, binary_message_string)
        """
        assert idlib.is_sloppy_id(counterparty_id), "precondition: `counterparty_id' must be  an id." + " -- " + "id: %s" % humanreadable.hr(id)

        counterparty_id = idlib.canonicalize(counterparty_id, "broker")<commit_msg>* remove debug move<commit_after>#  Copyright (c) 2001 Autonomous Zone Industries
#  This file is licensed under the
#    GNU Lesser General Public License v2.1.
#    See the file COPYING or visit http://www.gnu.org/ for details.

__revision__ = "$Id: Conversation.py,v 1.13 2003/02/02 22:12:49 myers_carpenter Exp $"

# Python standard library modules
import threading
import types
import traceback
import sys
from sha import sha
from time import time
import exceptions
import socket
import os
import types
from traceback import print_exc

# pyutil modules
from pyutil.debugprint import debugprint, debugstream
from pyutil import Cache
from pyutil import DoQ, nummedobj

# EGTP modules
from egtp import CommStrat
from egtp.CommHints import HINT_EXPECT_RESPONSE, HINT_EXPECT_MORE_TRANSACTIONS, HINT_EXPECT_NO_MORE_COMMS, HINT_EXPECT_TO_RESPOND, HINT_THIS_IS_A_RESPONSE, HINT_NO_HINT
from egtp import MojoMessage
from egtp import humanreadable, idlib, mencode, mojosixbit, std
from egtp.MojoHandicapper import DISQUALIFIED
from egtp.crypto import modval
from egtp.crypto import randsource

true = 1
false = 0

HANDLED = 0
EXPECTING_RESPONSE = 1

TUNING_FACTOR=float(2**8)

def is_mojo_message(thingie):
    return (type(thingie) is types.DictType) and (thingie.has_key('mojo header') or thingie.has_key('mojo message'))

class DebugDiagLoop(DoQ.DoQLoop, nummedobj.NummedObj):
    def __init__(self, cm):
        self.maxcbs = 0
        self.maxpcbs = 0
        self.maxoms = 0
        self.maxli2i = 0
        self.maxfps = 0
        DoQ.DoQLoop.__init__(self)
        nummedobj.NummedObj.__init__(self)
        self.cm = cm
        self.schedule_event()

    def event(self):
        if len(self.cm._callback_functions) > self.maxcbs:
            self.maxcbs = len(self.cm._callback_functions)
            debugprint("%s.event(): new max len(self.cm._callback_functions): %s, len(self.cm._posttimeout_callback_functions): %s, len(self.cm._map_inmsgid_to_info): %s, len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        if len(self.cm._posttimeout_callback_functions) > self.maxpcbs:
            self.maxpcbs = len(self.cm._posttimeout_callback_functions)
            debugprint("%s.event(): len(self.cm._callback_functions): %s, new max len(self.cm._posttimeout_callback_functions): %s, len(self.cm._map_inmsgid_to_info): %s, len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        if len(self.cm._callback_functions) > self.maxoms:
            self.maxoms = len(self.cm._callback_functions)
            debugprint("%s.event(): len(self.cm._callback_functions): %s, len(self.cm._posttimeout_callback_functions): %s, new max len(self.cm._callback_functions): %s, len(self.cm._map_inmsgid_to_info): %s, len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        if len(self.cm._map_inmsgid_to_info) > self.maxli2i:
            self.maxli2i = len(self.cm._map_inmsgid_to_info)
            debugprint("%s.event(): len(self.cm._callback_functions): %s, len(self.cm._posttimeout_callback_functions): %s, new max len(self.cm._map_inmsgid_to_info): %s, len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        if len(self.cm._map_cid_to_freshness_proof) > self.maxfps:
            self.maxfps = len(self.cm._map_cid_to_freshness_proof)
            debugprint("%s.event(): len(self.cm._callback_functions): %s, len(self.cm._posttimeout_callback_functions): %s, len(self.cm._map_inmsgid_to_info): %s, new max len(self.cm._map_cid_to_freshness_proof): %s\n", args=(self, len(self.cm._callback_functions), len(self.cm._posttimeout_callback_functions), len(self.cm._map_inmsgid_to_info), len(self.cm._map_cid_to_freshness_proof),), v=3, vs="Conversation")

        self.schedule_event(delay=60)

class ConversationManager:
    def __init__(self, MTM):
        self._MTM = MTM
        # maps first message ids to (counterparty_id, callback function, notes for callback, conversation type, post_timeout_callback_func, timeoutcheckerschedtime,)
        self.__callback_functions = {}

        # maps message id's of messages who's responses have timed out to (recipient_id, conversation type, time of timeout, post timeout callback function, notes [only if post timeout callback function])
        # Reminder: this indirectly holds references to the original outgoing message body as well as the metainfo used to send it.  That is often large.
        self.__posttimeout_callback_functions = Cache.LRUCache(maxsize=512)

        # maps message id to (binary counterparty_id, message type, response status)
        # where status is HANDLED or EXPECTING_RESPONSE
        # This data structure is used between receiving a specific initiating message and
        # sending the response to it.  It is not used for incoming response messages.
        self._map_inmsgid_to_info = {}

        # This is a map from counterparty_id to the binary msgId of the last message you
        # received from that counterparty.  We use the msgId in outgoing messages, thus proving
        # to the counterparty that our messages are fresh (i.e., they are not replay attacks or
        # other sneaky trickery).  Actually our current software does not check the incoming
        # freshness proofs, but this code ensures that when we ship a new, replay-attack-proof
        # version which _does_ verify freshness proofs, then older apps which are running _this_
        # version of our software will be able to interoperate with it.
        self._map_cid_to_freshness_proof = Cache.LRUCache(maxsize=512)

        self._in_message_num = 0L   # used only in debugging

    def shutdown(self):
        debugprint("self._map_inmsgid_to_info: %s\n", args=(self._map_inmsgid_to_info,), v=6, vs="debug")
        self.__callback_functions = {}
        # TODO: del this No other ref to this --icepick 2002-02-01
        # self._posttimeout_callback_functions.clear()
        self._map_inmsgid_to_info = {}
        self._map_cid_to_freshness_proof.clear()
        if hasattr(self, '_MTM'):
            del self._MTM  # break our circular reference

    def initiate_and_return_first_message(self, counterparty_id, conversationtype, firstmsgbody, outcome_func, timeout = 300, notes = None, mymetainfo=None, post_timeout_outcome_func=None):
        """
        @precondition: `counterparty_id' must be  an id.: idlib.is_sloppy_id(counterparty_id): "id: %s" % humanreadable.hr(id)

        @return: a tuple of (message_id, binary_message_string)
        """
        assert idlib.is_sloppy_id(counterparty_id), "precondition: `counterparty_id' must be  an id." + " -- " + "id: %s" % humanreadable.hr(id)

        counterparty_id = idlib.canonicalize(counterparty_id, "broker")
{'fraction_non_alphanumeric': 0.10032664489034064, 'fraction_numerical': 0.008532764482367842, 'mean_word_length': 4.1856204631870035, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6159667', 'n_tokens_mistral': 5006, 'n_tokens_neox': 4802, 'n_words': 1169}