diff --git a/kademlia/network.py b/kademlia/network.py index 6099336..8f68bc7 100644 --- a/kademlia/network.py +++ b/kademlia/network.py @@ -86,7 +86,6 @@ class SpiderCrawl(object): """ Handle the result of an iteration in C{_find}. """ - print "got some responses: ", responses toremove = [] for peerid, response in responses.items(): # response will be a tuple of (, ) @@ -113,7 +112,7 @@ class Server(object): to start listening as an active node on the network. """ - def __init__(self, ksize=20, alpha=3): + def __init__(self, ksize=20, alpha=3, id=None): """ Create a server instance. This will start listening on the given port. @@ -125,11 +124,17 @@ class Server(object): self.alpha = alpha self.log = Logger(system=self) storage = ForgetfulStorage() - self.node = Node(None, None, digest(random.getrandbits(255))) + self.node = Node(id or digest(random.getrandbits(255))) self.protocol = KademliaProtocol(self.node.id, storage, ksize) self.refreshLoop = LoopingCall(self.refreshTable).start(3600) def listen(self, port): + """ + Start listening on the given port. + + This is the same as calling: + C{reactor.listenUDP(port, server.protocol)} + """ return reactor.listenUDP(port, self.protocol) def refreshTable(self): @@ -139,12 +144,24 @@ class Server(object): """ ds = [] for id in self.protocol.getRefreshIDs(): - node = Node(None, None, id) + node = Node(id) nearest = self.protocol.router.findNeighbors(node, self.alpha) spider = SpiderCrawl(self.protocol, node, nearest) ds.append(spider.findNodes()) return defer.gatherResults(ds) + def bootstrappableNeighbors(self): + """ + Get a C{list} of (ip, port) C{tuple}s suitable for use as an argument + to the bootstrap method. + + The server should have been bootstrapped + already - this is just a utility for getting some neighbors and then + storing them if this server is going down for a while. When it comes + back up, the list of nodes can be used to bootstrap. + """ + return self.protocol.router.findNeighbors(self.node) + def bootstrap(self, addrs): """ Bootstrap the server by connecting to other known nodes in the network. @@ -155,7 +172,7 @@ class Server(object): nodes = [] for addr, result in results.items(): if result[0]: - nodes.append(Node(addr[0], addr[1], result[1])) + nodes.append(Node(result[1], addr[0], addr[1])) spider = SpiderCrawl(self.protocol, self.node, nodes, self.ksize, self.alpha) return spider.findNodes() @@ -170,7 +187,7 @@ class Server(object): @return: C{None} if not found, the value otherwise. """ - node = Node(None, None, digest(key)) + node = Node(digest(key)) nearest = self.protocol.router.findNeighbors(node) spider = SpiderCrawl(self.protocol, node, nearest, self.ksize, self.alpha) return spider.findValue() @@ -189,7 +206,7 @@ class Server(object): ds = [self.protocol.callStore(node, dkey, value) for node in nodes] return defer.gatherResults(ds) - node = Node(None, None, dkey) + node = Node(dkey) nearest = self.protocol.router.findNeighbors(node) spider = SpiderCrawl(self.protocol, node, nearest, self.ksize, self.alpha) return spider.findNodes().addCallback(store) diff --git a/kademlia/node.py b/kademlia/node.py index 0876c60..b8d8d59 100644 --- a/kademlia/node.py +++ b/kademlia/node.py @@ -3,10 +3,10 @@ import heapq class Node: - def __init__(self, ip, port, id): + def __init__(self, id, ip=None, port=None): + self.id = id self.ip = ip self.port = port - self.id = id self.long_id = long(id.encode('hex'), 16) def sameHomeAs(self, node): @@ -22,7 +22,7 @@ class Node: return iter([self.ip, self.port, self.id]) def __repr__(self): - return repr([self.ip, self.port, self.long_id]) + return repr([self.long_id, self.ip, self.port]) def __str__(self): return "%s:%s" % (self.ip, str(self.port)) diff --git a/kademlia/protocol.py b/kademlia/protocol.py index 4d10c79..82e111c 100644 --- a/kademlia/protocol.py +++ b/kademlia/protocol.py @@ -24,25 +24,25 @@ class KademliaProtocol(RPCProtocol): return ids def rpc_ping(self, sender, nodeid): - source = Node(sender[0], sender[1], nodeid) + source = Node(nodeid, sender[0], sender[1]) self.router.addContact(source) return self.sourceID def rpc_store(self, sender, nodeid, key, value): - source = Node(sender[0], sender[1], nodeid) + source = Node(nodeid, sender[0], sender[1]) self.router.addContact(source) self.log.debug("got a store request from %s, storing value" % str(sender)) self.storage[key] = value def rpc_find_node(self, sender, nodeid, key): self.log.info("finding neighbors of %i in local table" % long(nodeid.encode('hex'), 16)) - source = Node(sender[0], sender[1], nodeid) + source = Node(nodeid, sender[0], sender[1]) self.router.addContact(source) - node = Node(None, None, key) + node = Node(key) return map(tuple, self.router.findNeighbors(node, exclude=source)) def rpc_find_value(self, sender, nodeid, key): - source = Node(sender[0], sender[1], nodeid) + source = Node(nodeid, sender[0], sender[1]) self.router.addContact(source) value = self.storage.get(key, None) if value is None: diff --git a/kademlia/tests/test_node.py b/kademlia/tests/test_node.py index 921e046..58d71b2 100644 --- a/kademlia/tests/test_node.py +++ b/kademlia/tests/test_node.py @@ -11,7 +11,7 @@ from kademlia.tests.utils import mknode class NodeTest(unittest.TestCase): def test_longID(self): rid = hashlib.sha1(str(random.getrandbits(255))).digest() - n = Node(None, None, rid) + n = Node(rid) self.assertEqual(n.long_id, long(rid.encode('hex'), 16)) def test_distanceCalculation(self): @@ -19,8 +19,8 @@ class NodeTest(unittest.TestCase): ridtwo = hashlib.sha1(str(random.getrandbits(255))) shouldbe = long(ridone.hexdigest(), 16) ^ long(ridtwo.hexdigest(), 16) - none = Node(None, None, ridone.digest()) - ntwo = Node(None, None, ridtwo.digest()) + none = Node(ridone.digest()) + ntwo = Node(ridtwo.digest()) self.assertEqual(none.distanceTo(ntwo), shouldbe) @@ -37,7 +37,7 @@ class NodeHeapTest(unittest.TestCase): def test_iteration(self): heap = NodeHeap(5) - nodes = [mknode(id=digest(x)) for x in range(10)] + nodes = [mknode(digest(x)) for x in range(10)] for index, node in enumerate(nodes): heap.push(index, node) for index, node in enumerate(heap): @@ -46,7 +46,7 @@ class NodeHeapTest(unittest.TestCase): def test_remove(self): heap = NodeHeap(5) - nodes = [mknode(id=digest(x)) for x in range(10)] + nodes = [mknode(digest(x)) for x in range(10)] for index, node in enumerate(nodes): heap.push(index, node) diff --git a/kademlia/tests/utils.py b/kademlia/tests/utils.py index 4c8878d..1a13508 100644 --- a/kademlia/tests/utils.py +++ b/kademlia/tests/utils.py @@ -9,14 +9,14 @@ from kademlia.node import Node from kademlia.routing import RoutingTable -def mknode(ip=None, port=None, id=None, intid=None): +def mknode(id=None, ip=None, port=None, intid=None): """ Make a node. Created a random id if not specified. """ if intid is not None: id = pack('>l', intid) id = id or hashlib.sha1(str(random.getrandbits(255))).digest() - return Node(ip, port, id) + return Node(id, ip, port) class FakeProtocol(object): @@ -35,25 +35,25 @@ class FakeProtocol(object): return ids def rpc_ping(self, sender, nodeid): - source = Node(sender[0], sender[1], nodeid) + source = Node(nodeid, sender[0], sender[1]) self.router.addContact(source) return self.sourceID def rpc_store(self, sender, nodeid, key, value): - source = Node(sender[0], sender[1], nodeid) + source = Node(nodeid, sender[0], sender[1]) self.router.addContact(source) self.log.debug("got a store request from %s, storing value" % str(sender)) self.storage[key] = value def rpc_find_node(self, sender, nodeid, key): self.log.info("finding neighbors of %i in local table" % long(nodeid.encode('hex'), 16)) - source = Node(sender[0], sender[1], nodeid) + source = Node(nodeid, sender[0], sender[1]) self.router.addContact(source) - node = Node(None, None, key) + node = Node(key) return map(tuple, self.router.findNeighbors(node, exclude=source)) def rpc_find_value(self, sender, nodeid, key): - source = Node(sender[0], sender[1], nodeid) + source = Node(nodeid, sender[0], sender[1]) self.router.addContact(source) value = self.storage.get(key, None) if value is None: diff --git a/server.tac b/server.tac index f6d7abb..77a4768 100644 --- a/server.tac +++ b/server.tac @@ -1,9 +1,13 @@ from twisted.application import service, internet +from twisted.python.log import ILogObserver + import sys, os sys.path.append(os.path.dirname(__file__)) from kademlia.network import Server +from kademlia import log application = service.Application("kademlia") +application.setComponent(ILogObserver, log.FileLogObserver(sys.stdout, log.INFO).emit) kserver = Server() server = internet.UDPServer(1234, kserver.protocol) server.setServiceParent(application)