From ca49cde8f211163aac9dcf3e4b1233490fc01ca4 Mon Sep 17 00:00:00 2001 From: Brian Muller Date: Sat, 18 Jan 2014 12:55:34 -0500 Subject: [PATCH] set now returns true only if value set in at least one other place --- README.markdown | 18 +++++++++++++----- kademlia/network.py | 15 ++++++++++++--- kademlia/protocol.py | 1 + 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/README.markdown b/README.markdown index 9a677c9..ece7d8a 100644 --- a/README.markdown +++ b/README.markdown @@ -1,6 +1,8 @@ -# [Kademlia](http://en.wikipedia.org/wiki/Kademlia) in Python +# Kademlia Distributed Hash Table in Python [![Build Status](https://secure.travis-ci.org/bmuller/kademlia.png?branch=master)](https://travis-ci.org/bmuller/kademlia) +This library is an asynchronous Python implementation of the [Kademlia distributed hash table](http://en.wikipedia.org/wiki/Kademlia). It uses [Twisted]() to provide asynchronous communication. The nodes communicate using [RPC over UDP](https://github.com/bmuller/rpcudp) to communiate, meaning that it is capable of working behind a [NAT](http://en.wikipedia.org/wiki/NAT). + ## Installation ``` @@ -26,17 +28,16 @@ def quit(result): reactor.stop() def get(result, server): - reactor.stop() - #return server.get("a key").addCallback(quit) + return server.get("a key").addCallback(quit) def done(found, server): log.msg("Found nodes: %s" % found) return server.set("a key", "a value").addCallback(get, server) server = Server() -# next line, or use reactor.listenUDP(5678, server) +# next line, or use reactor.listenUDP(5678, server.protocol) server.listen(5678) -server.bootstrap([('127.0.0.1', 1234)]).addCallback(done, two) +server.bootstrap([('127.0.0.1', 1234)]).addCallback(done, server) reactor.run() ``` @@ -47,3 +48,10 @@ If all you want to do is run a local server, just start the example server: ``` twistd -noy server.tac ``` + +## Running Tests +To run tests: + +``` +trial kademlia +``` diff --git a/kademlia/network.py b/kademlia/network.py index 9df994b..51e1484 100644 --- a/kademlia/network.py +++ b/kademlia/network.py @@ -221,8 +221,6 @@ class Server(object): def set(self, key, value): """ Set the given key to the given value in the network. - - TODO - if no one responds, freak out """ self.log.debug("setting '%s' = '%s' on network" % (key, value)) dkey = digest(key) @@ -230,13 +228,24 @@ class Server(object): def store(nodes): self.log.info("setting '%s' on %s" % (key, map(str, nodes))) ds = [self.protocol.callStore(node, dkey, value) for node in nodes] - return defer.gatherResults(ds) + return defer.DeferredList(ds).addCallback(self._anyRespondSuccess) node = Node(dkey) nearest = self.protocol.router.findNeighbors(node) spider = SpiderCrawl(self.protocol, node, nearest, self.ksize, self.alpha) return spider.findNodes().addCallback(store) + def _anyRespondSuccess(self, 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 + def save(self, fname): data = { 'ksize': self.ksize, 'alpha': self.alpha, diff --git a/kademlia/protocol.py b/kademlia/protocol.py index 7e3def1..b4b8bfa 100644 --- a/kademlia/protocol.py +++ b/kademlia/protocol.py @@ -36,6 +36,7 @@ class KademliaProtocol(RPCProtocol): self.router.addContact(source) self.log.debug("got a store request from %s, storing value" % str(sender)) self.storage[key] = value + return True def rpc_find_node(self, sender, nodeid, key): self.log.info("finding neighbors of %i in local table" % long(nodeid.encode('hex'), 16))