예제 #1
0
    def get_closest(self, hash, count=None):
        """
        Gets the closest n contacts to a hash.

        :param hash: The hash to compare to.
        :type hash: :class:`common.Hash`
        :param count: Number of contacts to return.
        :type count: int.
        """
        if count is None:
            count = self.K
        targethash = (self.own_hash ^ hash)
        significant_bit = targethash.significant_bit()
        contacts = list()

        # Sorted Indices (for prox to the contact).
        # Ignore the one that is its own bucket to avoid any recursion.
        si = sorted([x for x in range(1, self.B + 1)],
                    key=lambda x: abs(x - significant_bit))

        for dindex in si:
            contacts += self._buckets[dindex].contacts
            if (len(contacts) >= count):
                return sorted(contacts, key=lambda x:
                              targethash.AbsDiff(self.own_hash ^ x.hash))[:count]
        Logger.debug("GET_CLOSEST ret: %s" % contacts)
        return contacts
예제 #2
0
    def get_closest(self, hash, count=None):
        """
        Gets the closest n contacts to a hash.

        :param hash: The hash to compare to.
        :type hash: :class:`common.Hash`
        :param count: Number of contacts to return.
        :type count: int.
        """
        if count is None:
            count = self.K
        targethash = (self.own_hash ^ hash)
        significant_bit = targethash.significant_bit()
        contacts = list()

        # Sorted Indices (for prox to the contact).
        # Ignore the one that is its own bucket to avoid any recursion.
        si = sorted([x for x in range(1, self.B + 1)],
                    key=lambda x: abs(x - significant_bit))

        for dindex in si:
            contacts += self._buckets[dindex].contacts
            if (len(contacts) >= count):
                return sorted(contacts,
                              key=lambda x: targethash.AbsDiff(self.own_hash ^
                                                               x.hash))[:count]
        Logger.debug("GET_CLOSEST ret: %s" % contacts)
        return contacts
예제 #3
0
    def rm_search(self, addr):
        """
        Filters all searches to remove the one given to it.

        :param addr: The address to remove.
        :type addr: :class:`common.Address`
        """
        self.in_progress = list(filter(lambda x: x.contact.address != addr,
                                       self.in_progress))
예제 #4
0
    def rm_search(self, addr):
        """
        Filters all searches to remove the one given to it.

        :param addr: The address to remove.
        :type addr: :class:`common.Address`
        """
        self.in_progress = list(
            filter(lambda x: x.contact.address != addr, self.in_progress))
예제 #5
0
    def translate(self, address):
        """
        Translates an :class:`~common.Address`
        a :class:`~common.Contact`.
        If no matching contact exists, one is created.

        :param address: The address data was received from.
        :type address: :class:`~common.Address`
        :param hash_: Given if this is a new client (on 'hello')
        :type hash_: :class:`~common.Hash`
        """
        # Get an existing contact
        try:
            contact = self._contacts_by_addr[str(address)]
            # Set the last time seen (to now)
            contact.last_seen = datetime.now()
            # Try associating the contact with a friend
            if not contact.needs_hash and not contact.has_friend:
                try:
                    self._friends[contact.hash.value].associate(contact)
                except KeyError:
                    pass
        # Errors if the contact does not exist
        except KeyError:
            contact = Contact(address)
            contact.channels['bytelynx'].crypto.p = self._dh_p
            contact.on_hash += self.on_contact_hash
            contact.on_death += self.clean_contact
            self._contacts_by_addr[str(address)] = contact
            self._on_changed()

        # Check for a sweep
        # TODO: Do we need to sweep contacts_by_hash?
        if datetime.now() - self._last_check > \
                timedelta(minutes=SWEEP_INTERVAL):
            self._last_check = datetime.now()
            del_time = datetime.now() - timedelta(minutes=EXPIRE_TIME)
            del_list = list(self._contacts_by_addr.values())\
                .where(lambda x: x.last_seen < del_time)

            for item in del_list:
                item.on_death()
        return contact
예제 #6
0
 def __init__(self, own_hash, target_hash, initial_contacts, K):
     """
     :param target_hash: The :hash that this shortlist is seaching for.
     :type target_hash: :class:`common.Hash`
     :param initial_contacts: Contacts to start the shorlist with.
     :type initial_contacts: [:class:`common.Contact`]
     """
     self.K = K
     self.search_space = list(SearchContact(contacted=False, contact=x)
                              for x in initial_contacts)
     self.own_hash = own_hash
     self.target_hash = target_hash
     self.on_full_or_found = Event('Shortlist.on_full_or_found')
     self.in_progress = []
     # Ensure we start off increasing.
     self.sort()
     self._closest = {}
     # Add the closest contact (our vote)
     # This only matters if there is 2 nodes
     c = self.find_min()
     if c is not None:
         self._add_closest(c.contact)
예제 #7
0
 def _clean_lists(self):
     for hash_, shortlist in self._shortlists.items():
         # Magic Number [1000]: convert seconds to ms
         # Magic Number [5]: tweakable to set how long to timeout requests
         alive = list(filter(lambda x: (datetime.now()-x.time).total_seconds() * 1000
                                        < x.contact.ping * 5,
                             shortlist.in_progress))
         # If any of the requests have timed out.
         if (len(alive) != len(shortlist.in_progress)):
             shortlist.in_progress = alive
         # Add any needed more requests to reach the parallel param A.
         while (len(shortlist.in_progress) < self.A):
             next_min = shortlist.get_next()
             # We have no more useable responses.
             if (next_min is None):
                 # No searches are in progress.
                 if (len(shortlist.in_progress) == 0):
                     shortlist.on_full_or_found(shortlist.target_hash,
                                                shortlist.closest)
                 break
             else:
                 self.on_search(hash_, next_min)
예제 #8
0
 def __init__(self, own_hash, target_hash, initial_contacts, K):
     """
     :param target_hash: The :hash that this shortlist is seaching for.
     :type target_hash: :class:`common.Hash`
     :param initial_contacts: Contacts to start the shorlist with.
     :type initial_contacts: [:class:`common.Contact`]
     """
     self.K = K
     self.search_space = list(
         SearchContact(contacted=False, contact=x)
         for x in initial_contacts)
     self.own_hash = own_hash
     self.target_hash = target_hash
     self.on_full_or_found = Event('Shortlist.on_full_or_found')
     self.in_progress = []
     # Ensure we start off increasing.
     self.sort()
     self._closest = {}
     # Add the closest contact (our vote)
     # This only matters if there is 2 nodes
     c = self.find_min()
     if c is not None:
         self._add_closest(c.contact)
예제 #9
0
 def _clean_lists(self):
     for hash_, shortlist in self._shortlists.items():
         # Magic Number [1000]: convert seconds to ms
         # Magic Number [5]: tweakable to set how long to timeout requests
         alive = list(
             filter(
                 lambda x: (datetime.now() - x.time).total_seconds() * 1000
                 < x.contact.ping * 5, shortlist.in_progress))
         # If any of the requests have timed out.
         if (len(alive) != len(shortlist.in_progress)):
             shortlist.in_progress = alive
         # Add any needed more requests to reach the parallel param A.
         while (len(shortlist.in_progress) < self.A):
             next_min = shortlist.get_next()
             # We have no more useable responses.
             if (next_min is None):
                 # No searches are in progress.
                 if (len(shortlist.in_progress) == 0):
                     shortlist.on_full_or_found(shortlist.target_hash,
                                                shortlist.closest)
                 break
             else:
                 self.on_search(hash_, next_min)
예제 #10
0
 def __init__(self, K):
     self.K = K
     self.contacts = list()
     self.waitlist = list()
     self.on_added = Event('Bucket.on_added')
     self.on_removed = Event('Bucket.on_removed')
예제 #11
0
 def friends(self):
     return list(self._friends.values())
예제 #12
0
 def net_contacts(self):
     return list(self._contacts_by_addr.values())
예제 #13
0
 def __init__(self, K):
     self.K = K
     self.contacts = list()
     self.waitlist = list()
     self.on_added = Event('Bucket.on_added')
     self.on_removed = Event('Bucket.on_removed')