<commit_before>"""
Package for interacting on the network at a high level.

Copyright (c) 2014 <NAME>
Copyright (c) 2015 OpenBazaar
"""

import pickle
import httplib
import random
from binascii import hexlify
from twisted.internet.task import LoopingCall
from twisted.internet import defer, reactor, task

import nacl.signing
import nacl.hash
import nacl.encoding

from seed import peers
from log import Logger
from dht.protocol import KademliaProtocol
from dht.utils import deferredDict, digest
from dht.storage import ForgetfulStorage
from dht.node import Node
from dht.crawling import ValueSpiderCrawl
from dht.crawling import NodeSpiderCrawl

from protos import objects

from config import SEEDS, SEEDS_TESTNET
from random import shuffle


def _anyRespondSuccess(responses):
    """
    Given the result of a DeferredList of calls to peers, ensure that at least
    one of them was contacted and responded with a Truthy result.
    """
    for deferSuccess, result in responses:
        peerReached, peerResponse = result
        if deferSuccess and peerReached and peerResponse:
            return True
    return False


class Server(object):
    """
    High level view of a node instance.  This is the object that should be created
    to start listening as an active node on the network.
    """

    def __init__(self, node, db, signing_key, ksize=20, alpha=3, storage=None):
        """
        Create a server instance.  This will start listening on the given port.

        Args:
            node: The node instance for this peer. It must contain (at minimum) an ID,
                public key, ip address, and port.
            ksize (int): The k parameter from the paper
            alpha (int): The alpha parameter from the paper
            storage: An instance that implements :interface:`~dht.storage.IStorage`
        """
        self.ksize = ksize
        self.alpha = alpha
        self.log = Logger(system=self)
        self.storage = storage or ForgetfulStorage()
        self.node = node
        self.protocol = KademliaProtocol(self.node, self.storage, ksize, db, signing_key)
        self.refreshLoop = LoopingCall(self.refreshTable).start(3600)

    def listen(self, port):
        """
        Start listening on the given port.

        This is the same as calling::

            reactor.listenUDP(port, server.protocol)
        """
        return reactor.listenUDP(port, self.protocol)

    def refreshTable(self):
        """
        Refresh buckets that haven't had any lookups in the last hour
        (per section 2.3 of the paper).
        """
        ds = []
        refresh_ids = self.protocol.getRefreshIDs()
        refresh_ids.append(digest(random.getrandbits(255)))  # random node so we get more diversity
        for rid in refresh_ids:
            node = Node(rid)
            nearest = self.protocol.router.findNeighbors(node, self.alpha)
            spider = NodeSpiderCrawl(self.protocol, node, nearest, self.ksize, self.alpha)
            ds.append(spider.find())

        def republishKeys(_):
            for bucket in self.protocol.router.buckets:
                for node in bucket.nodes.values():
                    self.protocol.transferKeyValues(node)

        return defer.gatherResults(ds).addCallback(republishKeys)<commit_msg>Only republish to your bucket<commit_after>"""
Package for interacting on the network at a high level.

Copyright (c) 2014 <NAME>
Copyright (c) 2015 OpenBazaar
"""

import pickle
import httplib
import random
from binascii import hexlify
from twisted.internet.task import LoopingCall
from twisted.internet import defer, reactor, task

import nacl.signing
import nacl.hash
import nacl.encoding

from seed import peers
from log import Logger
from dht.protocol import KademliaProtocol
from dht.utils import deferredDict, digest
from dht.storage import ForgetfulStorage
from dht.node import Node
from dht.crawling import ValueSpiderCrawl
from dht.crawling import NodeSpiderCrawl

from protos import objects

from config import SEEDS, SEEDS_TESTNET
from random import shuffle


def _anyRespondSuccess(responses):
    """
    Given the result of a DeferredList of calls to peers, ensure that at least
    one of them was contacted and responded with a Truthy result.
    """
    for deferSuccess, result in responses:
        peerReached, peerResponse = result
        if deferSuccess and peerReached and peerResponse:
            return True
    return False


class Server(object):
    """
    High level view of a node instance.  This is the object that should be created
    to start listening as an active node on the network.
    """

    def __init__(self, node, db, signing_key, ksize=20, alpha=3, storage=None):
        """
        Create a server instance.  This will start listening on the given port.

        Args:
            node: The node instance for this peer. It must contain (at minimum) an ID,
                public key, ip address, and port.
            ksize (int): The k parameter from the paper
            alpha (int): The alpha parameter from the paper
            storage: An instance that implements :interface:`~dht.storage.IStorage`
        """
        self.ksize = ksize
        self.alpha = alpha
        self.log = Logger(system=self)
        self.storage = storage or ForgetfulStorage()
        self.node = node
        self.protocol = KademliaProtocol(self.node, self.storage, ksize, db, signing_key)
        self.refreshLoop = LoopingCall(self.refreshTable).start(3600)

    def listen(self, port):
        """
        Start listening on the given port.

        This is the same as calling::

            reactor.listenUDP(port, server.protocol)
        """
        return reactor.listenUDP(port, self.protocol)

    def refreshTable(self):
        """
        Refresh buckets that haven't had any lookups in the last hour
        (per section 2.3 of the paper).
        """
        ds = []
        refresh_ids = self.protocol.getRefreshIDs()
        refresh_ids.append(digest(random.getrandbits(255)))  # random node so we get more diversity
        for rid in refresh_ids:
            node = Node(rid)
            nearest = self.protocol.router.findNeighbors(node, self.alpha)
            spider = NodeSpiderCrawl(self.protocol, node, nearest, self.ksize, self.alpha)
            ds.append(spider.find())

        def republishKeys(_):
            self.log.debug("Republishing key/values...")
            neighbors = self.protocol.router.findNeighbors(self.node, exclude=self.node)
            for node in neighbors:
                self.protocol.transferKeyValues(node)

        return defer.gatherResults(ds).addCallback(republishKeys)
{'fraction_non_alphanumeric': 0.07361778846153846, 'fraction_numerical': 0.006009615384615385, 'mean_word_length': 2.692179700499168, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '294281', 'n_tokens_mistral': 1868, 'n_tokens_neox': 1782, 'n_words': 654}