set now returns true only if value set in at least one other place
This commit is contained in:
parent
e99d87c0e8
commit
ca49cde8f2
@ -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)
|
[![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
|
## Installation
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -26,17 +28,16 @@ def quit(result):
|
|||||||
reactor.stop()
|
reactor.stop()
|
||||||
|
|
||||||
def get(result, server):
|
def get(result, server):
|
||||||
reactor.stop()
|
return server.get("a key").addCallback(quit)
|
||||||
#return server.get("a key").addCallback(quit)
|
|
||||||
|
|
||||||
def done(found, server):
|
def done(found, server):
|
||||||
log.msg("Found nodes: %s" % found)
|
log.msg("Found nodes: %s" % found)
|
||||||
return server.set("a key", "a value").addCallback(get, server)
|
return server.set("a key", "a value").addCallback(get, server)
|
||||||
|
|
||||||
server = Server()
|
server = Server()
|
||||||
# next line, or use reactor.listenUDP(5678, server)
|
# next line, or use reactor.listenUDP(5678, server.protocol)
|
||||||
server.listen(5678)
|
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()
|
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
|
twistd -noy server.tac
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
To run tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
trial kademlia
|
||||||
|
```
|
||||||
|
@ -221,8 +221,6 @@ class Server(object):
|
|||||||
def set(self, key, value):
|
def set(self, key, value):
|
||||||
"""
|
"""
|
||||||
Set the given key to the given value in the network.
|
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))
|
self.log.debug("setting '%s' = '%s' on network" % (key, value))
|
||||||
dkey = digest(key)
|
dkey = digest(key)
|
||||||
@ -230,13 +228,24 @@ class Server(object):
|
|||||||
def store(nodes):
|
def store(nodes):
|
||||||
self.log.info("setting '%s' on %s" % (key, map(str, nodes)))
|
self.log.info("setting '%s' on %s" % (key, map(str, nodes)))
|
||||||
ds = [self.protocol.callStore(node, dkey, value) for node in 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)
|
node = Node(dkey)
|
||||||
nearest = self.protocol.router.findNeighbors(node)
|
nearest = self.protocol.router.findNeighbors(node)
|
||||||
spider = SpiderCrawl(self.protocol, node, nearest, self.ksize, self.alpha)
|
spider = SpiderCrawl(self.protocol, node, nearest, self.ksize, self.alpha)
|
||||||
return spider.findNodes().addCallback(store)
|
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):
|
def save(self, fname):
|
||||||
data = { 'ksize': self.ksize,
|
data = { 'ksize': self.ksize,
|
||||||
'alpha': self.alpha,
|
'alpha': self.alpha,
|
||||||
|
@ -36,6 +36,7 @@ class KademliaProtocol(RPCProtocol):
|
|||||||
self.router.addContact(source)
|
self.router.addContact(source)
|
||||||
self.log.debug("got a store request from %s, storing value" % str(sender))
|
self.log.debug("got a store request from %s, storing value" % str(sender))
|
||||||
self.storage[key] = value
|
self.storage[key] = value
|
||||||
|
return True
|
||||||
|
|
||||||
def rpc_find_node(self, sender, nodeid, key):
|
def rpc_find_node(self, sender, nodeid, key):
|
||||||
self.log.info("finding neighbors of %i in local table" % long(nodeid.encode('hex'), 16))
|
self.log.info("finding neighbors of %i in local table" % long(nodeid.encode('hex'), 16))
|
||||||
|
Loading…
Reference in New Issue
Block a user