added a query script and test for utils
This commit is contained in:
parent
d126479bce
commit
c0b05eb6d3
@ -20,6 +20,7 @@ This library aims to be as close to a reference implementation of the `Kademlia
|
||||
:titlesonly:
|
||||
|
||||
intro
|
||||
querying
|
||||
source/modules
|
||||
|
||||
|
||||
|
12
docs/querying.rst
Normal file
12
docs/querying.rst
Normal file
@ -0,0 +1,12 @@
|
||||
Querying the DHT
|
||||
==================
|
||||
|
||||
If you just want to query the network, you can use the example query script. For instance::
|
||||
|
||||
$ python examples/query.py 1.2.3.4 8468 SpecialKey
|
||||
|
||||
The query script is simple:
|
||||
|
||||
.. literalinclude:: ../examples/query.py
|
||||
|
||||
Check out the examples folder for other examples.
|
33
examples/query.py
Normal file
33
examples/query.py
Normal file
@ -0,0 +1,33 @@
|
||||
from twisted.internet import reactor
|
||||
from twisted.python import log
|
||||
from kademlia.network import Server
|
||||
import sys
|
||||
|
||||
log.startLogging(sys.stdout)
|
||||
|
||||
if len(sys.argv) != 4:
|
||||
print "Usage: python query.py <bootstrap ip> <bootstrap port> <key>"
|
||||
sys.exit(1)
|
||||
|
||||
ip = sys.argv[1]
|
||||
port = int(sys.argv[2])
|
||||
key = sys.argv[3]
|
||||
|
||||
print "Getting %s (with bootstrap %s:%i)" % (key, ip, port)
|
||||
|
||||
def done(result):
|
||||
print "Key result:"
|
||||
print result
|
||||
reactor.stop()
|
||||
|
||||
def bootstrapDone(found, server, key):
|
||||
if len(found) == 0:
|
||||
print "Could not connect to the bootstrap server."
|
||||
reactor.stop()
|
||||
server.get(key).addCallback(done)
|
||||
|
||||
server = Server()
|
||||
server.listen(port)
|
||||
server.bootstrap([(ip, port)]).addCallback(bootstrapDone, server, key)
|
||||
|
||||
reactor.run()
|
@ -152,7 +152,7 @@ class RoutingTable(object):
|
||||
if bucket.addNode(node):
|
||||
return
|
||||
|
||||
# Per section 4.2 of paper, split if the bucket has the node in it's range
|
||||
# Per section 4.2 of paper, split if the bucket has the node in its range
|
||||
# or if the depth is not congruent to 0 mod 5
|
||||
if bucket.hasInRange(self.node) or bucket.depth() % 5 != 0:
|
||||
self.splitBucket(index)
|
||||
|
37
kademlia/tests/test_utils.py
Normal file
37
kademlia/tests/test_utils.py
Normal file
@ -0,0 +1,37 @@
|
||||
import hashlib
|
||||
|
||||
from twisted.trial import unittest
|
||||
|
||||
from kademlia.utils import digest, sharedPrefix, OrderedSet
|
||||
|
||||
|
||||
class UtilsTest(unittest.TestCase):
|
||||
def test_digest(self):
|
||||
d = hashlib.sha1('1').digest()
|
||||
self.assertEqual(d, digest(1))
|
||||
|
||||
d = hashlib.sha1('another').digest()
|
||||
self.assertEqual(d, digest('another'))
|
||||
|
||||
def test_sharedPrefix(self):
|
||||
args = ['prefix', 'prefixasdf', 'prefix', 'prefixxxx']
|
||||
self.assertEqual(sharedPrefix(args), 'prefix')
|
||||
|
||||
args = ['p', 'prefixasdf', 'prefix', 'prefixxxx']
|
||||
self.assertEqual(sharedPrefix(args), 'p')
|
||||
|
||||
args = ['one', 'two']
|
||||
self.assertEqual(sharedPrefix(args), '')
|
||||
|
||||
args = ['hi']
|
||||
self.assertEqual(sharedPrefix(args), 'hi')
|
||||
|
||||
|
||||
class OrderedSetTest(unittest.TestCase):
|
||||
def test_order(self):
|
||||
o = OrderedSet()
|
||||
o.push('1')
|
||||
o.push('1')
|
||||
o.push('2')
|
||||
o.push('1')
|
||||
self.assertEqual(o, ['2', '1'])
|
@ -15,12 +15,14 @@ def digest(s):
|
||||
|
||||
def deferredDict(d):
|
||||
"""
|
||||
Just like a C{defer.DeferredList} but instead accepts and returns a C{dict}.
|
||||
Just like a :class:`defer.DeferredList` but instead accepts and returns a :class:`dict`.
|
||||
|
||||
@param d: A C{dict} whose values are all C{Deferred} objects.
|
||||
Args:
|
||||
d: A :class:`dict` whose values are all :class:`defer.Deferred` objects.
|
||||
|
||||
@return: A C{DeferredList} whose callback will be given a dictionary whose
|
||||
keys are the same as the parameter C{d}'s and whose values are the results
|
||||
Returns:
|
||||
:class:`defer.DeferredList` whose callback will be given a dictionary whose
|
||||
keys are the same as the parameter :obj:`d` and whose values are the results
|
||||
of each individual deferred call.
|
||||
"""
|
||||
if len(d) == 0:
|
||||
@ -37,7 +39,15 @@ def deferredDict(d):
|
||||
|
||||
|
||||
class OrderedSet(list):
|
||||
"""
|
||||
Acts like a list in all ways, except in the behavior of the :meth:`push` method.
|
||||
"""
|
||||
|
||||
def push(self, thing):
|
||||
"""
|
||||
1. If the item exists in the list, it's removed
|
||||
2. The item is pushed to the end of the list
|
||||
"""
|
||||
if thing in self:
|
||||
self.remove(thing)
|
||||
self.append(thing)
|
||||
@ -47,8 +57,11 @@ def sharedPrefix(args):
|
||||
"""
|
||||
Find the shared prefix between the strings.
|
||||
|
||||
For instance, sharedPrefix(['blahblah', 'blahwhat']) is
|
||||
'blah'.
|
||||
For instance:
|
||||
|
||||
sharedPrefix(['blahblah', 'blahwhat'])
|
||||
|
||||
returns 'blah'.
|
||||
"""
|
||||
i = 0
|
||||
while i < min(map(len, args)):
|
||||
|
Loading…
Reference in New Issue
Block a user