forked from LBRYCommunity/lbry-sdk
formatting
This commit is contained in:
parent
5ec891c9ac
commit
850f51140e
13 changed files with 105 additions and 65 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,6 +6,7 @@
|
|||
*.log
|
||||
*.pem
|
||||
*.decTest
|
||||
*.prof
|
||||
.#*
|
||||
|
||||
/build
|
||||
|
|
|
@ -14,6 +14,7 @@ class Contact(object):
|
|||
This class contains information on a single remote contact, and also
|
||||
provides a direct RPC API to the remote node which it represents
|
||||
"""
|
||||
|
||||
def __init__(self, id, ipAddress, udpPort, networkProtocol, firstComm=0):
|
||||
self.id = id
|
||||
self.address = ipAddress
|
||||
|
@ -60,6 +61,8 @@ class Contact(object):
|
|||
This happens via this contact's C{_networkProtocol} object (i.e. the
|
||||
host Node's C{_protocol} object).
|
||||
"""
|
||||
|
||||
def _sendRPC(*args, **kwargs):
|
||||
return self._networkProtocol.sendRPC(self, name, args, **kwargs)
|
||||
|
||||
return _sendRPC
|
||||
|
|
|
@ -12,21 +12,23 @@ import time
|
|||
import constants
|
||||
|
||||
|
||||
|
||||
class DataStore(UserDict.DictMixin):
|
||||
""" Interface for classes implementing physical storage (for data
|
||||
published via the "STORE" RPC) for the Kademlia DHT
|
||||
|
||||
@note: This provides an interface for a dict-like object
|
||||
"""
|
||||
|
||||
def keys(self):
|
||||
""" Return a list of the keys in this data store """
|
||||
|
||||
def addPeerToBlob(self, key, value, lastPublished, originallyPublished, originalPublisherID):
|
||||
pass
|
||||
|
||||
|
||||
class DictDataStore(DataStore):
|
||||
""" A datastore using an in-memory Python dictionary """
|
||||
|
||||
def __init__(self):
|
||||
# Dictionary format:
|
||||
# { <key>: (<value>, <lastPublished>, <originallyPublished> <originalPublisherID>) }
|
||||
|
@ -38,10 +40,12 @@ class DictDataStore(DataStore):
|
|||
|
||||
def removeExpiredPeers(self):
|
||||
now = int(time.time())
|
||||
|
||||
def notExpired(peer):
|
||||
if (now - peer[2]) > constants.dataExpireTimeout:
|
||||
return False
|
||||
return True
|
||||
|
||||
for key in self._dict.keys():
|
||||
unexpired_peers = filter(notExpired, self._dict[key])
|
||||
self._dict[key] = unexpired_peers
|
||||
|
|
|
@ -12,12 +12,14 @@ class DecodeError(Exception):
|
|||
fails
|
||||
"""
|
||||
|
||||
|
||||
class Encoding(object):
|
||||
""" Interface for RPC message encoders/decoders
|
||||
|
||||
All encoding implementations used with this library should inherit and
|
||||
implement this.
|
||||
"""
|
||||
|
||||
def encode(self, data):
|
||||
""" Encode the specified data
|
||||
|
||||
|
@ -31,6 +33,7 @@ class Encoding(object):
|
|||
@return: The encoded data
|
||||
@rtype: str
|
||||
"""
|
||||
|
||||
def decode(self, data):
|
||||
""" Decode the specified data string
|
||||
|
||||
|
@ -40,6 +43,7 @@ class Encoding(object):
|
|||
@return: The decoded data (in its correct type)
|
||||
"""
|
||||
|
||||
|
||||
class Bencode(Encoding):
|
||||
""" Implementation of a Bencode-based algorithm (Bencode is the encoding
|
||||
algorithm used by Bittorrent).
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
from collections import Counter
|
||||
import datetime
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
import constants
|
||||
|
||||
|
||||
class BucketFull(Exception):
|
||||
""" Raised when the bucket is full """
|
||||
|
||||
|
@ -16,6 +17,7 @@ class BucketFull(Exception):
|
|||
class KBucket(object):
|
||||
""" Description - later
|
||||
"""
|
||||
|
||||
def __init__(self, rangeMin, rangeMax):
|
||||
"""
|
||||
@param rangeMin: The lower boundary for the range in the n-bit ID
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
import msgtypes
|
||||
|
||||
|
||||
class MessageTranslator(object):
|
||||
""" Interface for RPC message translators/formatters
|
||||
|
||||
|
@ -16,6 +17,7 @@ class MessageTranslator(object):
|
|||
the classes used internally by this Kademlia implementation and the actual
|
||||
data that is transmitted between nodes.
|
||||
"""
|
||||
|
||||
def fromPrimitive(self, msgPrimitive):
|
||||
""" Create an RPC Message from a message's string representation
|
||||
|
||||
|
@ -37,6 +39,7 @@ class MessageTranslator(object):
|
|||
@rtype: str, int, list or dict
|
||||
"""
|
||||
|
||||
|
||||
class DefaultFormat(MessageTranslator):
|
||||
""" The default on-the-wire message format for this library """
|
||||
typeRequest, typeResponse, typeError = range(3)
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
import hashlib
|
||||
import random
|
||||
|
||||
|
||||
class Message(object):
|
||||
""" Base class for messages - all "unknown" messages use this class """
|
||||
|
||||
def __init__(self, rpcID, nodeID):
|
||||
self.id = rpcID
|
||||
self.nodeID = nodeID
|
||||
|
@ -19,6 +21,7 @@ class Message(object):
|
|||
|
||||
class RequestMessage(Message):
|
||||
""" Message containing an RPC request """
|
||||
|
||||
def __init__(self, nodeID, method, methodArgs, rpcID=None):
|
||||
if rpcID == None:
|
||||
hash = hashlib.sha384()
|
||||
|
@ -31,6 +34,7 @@ class RequestMessage(Message):
|
|||
|
||||
class ResponseMessage(Message):
|
||||
""" Message containing the result from a successful RPC request """
|
||||
|
||||
def __init__(self, rpcID, nodeID, response):
|
||||
Message.__init__(self, rpcID, nodeID)
|
||||
self.response = response
|
||||
|
@ -38,6 +42,7 @@ class ResponseMessage(Message):
|
|||
|
||||
class ErrorMessage(ResponseMessage):
|
||||
""" Message containing the error from an unsuccessful RPC request """
|
||||
|
||||
def __init__(self, rpcID, nodeID, exceptionType, errorMessage):
|
||||
ResponseMessage.__init__(self, rpcID, nodeID, errorMessage)
|
||||
if isinstance(exceptionType, type):
|
||||
|
|
|
@ -27,7 +27,6 @@ from contact import Contact
|
|||
from hashwatcher import HashWatcher
|
||||
import logging
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -51,6 +50,7 @@ class Node(object):
|
|||
In Entangled, all interactions with the Kademlia network by a client
|
||||
application is performed via this class (or a subclass).
|
||||
"""
|
||||
|
||||
def __init__(self, id=None, udpPort=4000, dataStore=None,
|
||||
routingTableClass=None, networkProtocol=None, lbryid=None,
|
||||
externalIP=None):
|
||||
|
@ -137,7 +137,6 @@ class Node(object):
|
|||
self._listeningPort.stopListening()
|
||||
self.hash_watcher.stop()
|
||||
|
||||
|
||||
def joinNetwork(self, knownNodeAddresses=None):
|
||||
""" Causes the Node to join the Kademlia network; normally, this
|
||||
should be called before any other DHT operations.
|
||||
|
@ -351,6 +350,7 @@ class Node(object):
|
|||
"""
|
||||
# Prepare a callback for this operation
|
||||
outerDf = defer.Deferred()
|
||||
|
||||
def checkResult(result):
|
||||
if type(result) == dict:
|
||||
# We have found the value; now see who was the closest contact without it...
|
||||
|
@ -416,6 +416,7 @@ class Node(object):
|
|||
return contact
|
||||
else:
|
||||
return None
|
||||
|
||||
df = self.iterativeFindNode(contactID)
|
||||
df.addCallback(parseResults)
|
||||
return df
|
||||
|
@ -618,6 +619,7 @@ class Node(object):
|
|||
def _refreshRoutingTable(self):
|
||||
nodeIDs = self._routingTable.getRefreshList(0, False)
|
||||
outerDf = defer.Deferred()
|
||||
|
||||
def searchForNextNodeID(dfResult=None):
|
||||
if len(nodeIDs) > 0:
|
||||
searchID = nodeIDs.pop()
|
||||
|
@ -626,11 +628,11 @@ class Node(object):
|
|||
else:
|
||||
# If this is reached, we have finished refreshing the routing table
|
||||
outerDf.callback(None)
|
||||
|
||||
# Start the refreshing cycle
|
||||
searchForNextNodeID()
|
||||
return outerDf
|
||||
|
||||
|
||||
def _scheduleNextNodeRefresh(self, *args):
|
||||
self.next_refresh_call = twisted.internet.reactor.callLater(
|
||||
constants.checkRefreshInterval, self._refreshNode)
|
||||
|
@ -850,6 +852,7 @@ class Distance(object):
|
|||
Frequently we re-use one of the points so as an optimization
|
||||
we pre-calculate the long value of that point.
|
||||
"""
|
||||
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
self.val_key_one = long(key.encode('hex'), 16)
|
||||
|
@ -879,6 +882,7 @@ class ExpensiveSort(object):
|
|||
key: callable, like `key` in normal python sort
|
||||
attr: the attribute name used to cache the value on each item.
|
||||
"""
|
||||
|
||||
def __init__(self, to_sort, key, attr='__value'):
|
||||
self.to_sort = to_sort
|
||||
self.key = key
|
||||
|
@ -923,5 +927,6 @@ def main():
|
|||
node.joinNetwork(known_nodes)
|
||||
twisted.internet.reactor.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -24,13 +24,13 @@ import msgtypes
|
|||
import msgformat
|
||||
from contact import Contact
|
||||
|
||||
|
||||
reactor = twisted.internet.reactor
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TimeoutError(Exception):
|
||||
""" Raised when a RPC times out """
|
||||
|
||||
def __init__(self, remote_contact_id):
|
||||
# remote_contact_id is a binary blob so we need to convert it
|
||||
# into something more readable
|
||||
|
@ -64,7 +64,6 @@ class KademliaProtocol(protocol.DatagramProtocol):
|
|||
""" Implements all low-level network-related functions of a Kademlia node """
|
||||
msgSizeLimit = constants.udpDatagramMaxSize - 26
|
||||
|
||||
|
||||
def __init__(self, node, msgEncoder=encoding.Bencode(),
|
||||
msgTranslator=msgformat.DefaultFormat()):
|
||||
self._node = node
|
||||
|
@ -281,6 +280,7 @@ class KademliaProtocol(protocol.DatagramProtocol):
|
|||
|
||||
def _handleRPC(self, senderContact, rpcID, method, args):
|
||||
""" Executes a local function in response to an RPC request """
|
||||
|
||||
# Set up the deferred callchain
|
||||
def handleError(f):
|
||||
self._sendError(senderContact, rpcID, f.type, f.getErrorMessage())
|
||||
|
|
|
@ -5,24 +5,28 @@
|
|||
# The docstrings in this module contain epytext markup; API documentation
|
||||
# may be created by processing this file with epydoc: http://epydoc.sf.net
|
||||
|
||||
import time, random
|
||||
|
||||
import time
|
||||
import random
|
||||
import constants
|
||||
import kbucket
|
||||
|
||||
from protocol import TimeoutError
|
||||
|
||||
|
||||
class RoutingTable(object):
|
||||
""" Interface for RPC message translators/formatters
|
||||
|
||||
Classes inheriting from this should provide a suitable routing table for
|
||||
a parent Node object (i.e. the local entity in the Kademlia network)
|
||||
"""
|
||||
|
||||
def __init__(self, parentNodeID):
|
||||
"""
|
||||
@param parentNodeID: The n-bit node ID of the node to which this
|
||||
routing table belongs
|
||||
@type parentNodeID: str
|
||||
"""
|
||||
|
||||
def addContact(self, contact):
|
||||
""" Add the given contact to the correct k-bucket; if it already
|
||||
exists, its status will be updated
|
||||
|
@ -51,12 +55,14 @@ class RoutingTable(object):
|
|||
node is returning all of the contacts that it knows of.
|
||||
@rtype: list
|
||||
"""
|
||||
|
||||
def getContact(self, contactID):
|
||||
""" Returns the (known) contact with the specified node ID
|
||||
|
||||
@raise ValueError: No contact with the specified contact ID is known
|
||||
by this node
|
||||
"""
|
||||
|
||||
def getRefreshList(self, startIndex=0, force=False):
|
||||
""" Finds all k-buckets that need refreshing, starting at the
|
||||
k-bucket with the specified index, and returns IDs to be searched for
|
||||
|
@ -78,6 +84,7 @@ class RoutingTable(object):
|
|||
in order to refresh the routing Table
|
||||
@rtype: list
|
||||
"""
|
||||
|
||||
def removeContact(self, contactID):
|
||||
""" Remove the contact with the specified node ID from the routing
|
||||
table
|
||||
|
@ -85,6 +92,7 @@ class RoutingTable(object):
|
|||
@param contactID: The node ID of the contact to remove
|
||||
@type contactID: str
|
||||
"""
|
||||
|
||||
def touchKBucket(self, key):
|
||||
""" Update the "last accessed" timestamp of the k-bucket which covers
|
||||
the range containing the specified key in the key/ID space
|
||||
|
@ -109,6 +117,7 @@ class TreeRoutingTable(RoutingTable):
|
|||
C{PING} RPC-based k-bucket eviction algorithm described in section 2.2 of
|
||||
that paper.
|
||||
"""
|
||||
|
||||
def __init__(self, parentNodeID):
|
||||
"""
|
||||
@param parentNodeID: The n-bit node ID of the node to which this
|
||||
|
@ -349,11 +358,13 @@ class TreeRoutingTable(RoutingTable):
|
|||
for contact in newBucket._contacts:
|
||||
oldBucket.removeContact(contact)
|
||||
|
||||
|
||||
class OptimizedTreeRoutingTable(TreeRoutingTable):
|
||||
""" A version of the "tree"-type routing table specified by Kademlia,
|
||||
along with contact accounting optimizations specified in section 4.1 of
|
||||
of the 13-page version of the Kademlia paper.
|
||||
"""
|
||||
|
||||
def __init__(self, parentNodeID):
|
||||
TreeRoutingTable.__init__(self, parentNodeID)
|
||||
# Cache containing nodes eligible to replace stale k-bucket entries
|
||||
|
|
|
@ -140,4 +140,7 @@ def start_server_and_listen(launchui, use_auth, analytics_manager, max_tries=5):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# import cProfile
|
||||
# import time
|
||||
# cProfile.run('start()', '/home/grin/code/lbry/lbry/daemonstats_' + time.strftime("%Y%m%d_%H%M%S"))
|
||||
start()
|
||||
|
|
Loading…
Reference in a new issue