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:
|
:titlesonly:
|
||||||
|
|
||||||
intro
|
intro
|
||||||
|
querying
|
||||||
source/modules
|
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):
|
if bucket.addNode(node):
|
||||||
return
|
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
|
# or if the depth is not congruent to 0 mod 5
|
||||||
if bucket.hasInRange(self.node) or bucket.depth() % 5 != 0:
|
if bucket.hasInRange(self.node) or bucket.depth() % 5 != 0:
|
||||||
self.splitBucket(index)
|
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):
|
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
|
Returns:
|
||||||
keys are the same as the parameter C{d}'s and whose values are the results
|
: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.
|
of each individual deferred call.
|
||||||
"""
|
"""
|
||||||
if len(d) == 0:
|
if len(d) == 0:
|
||||||
@ -37,7 +39,15 @@ def deferredDict(d):
|
|||||||
|
|
||||||
|
|
||||||
class OrderedSet(list):
|
class OrderedSet(list):
|
||||||
|
"""
|
||||||
|
Acts like a list in all ways, except in the behavior of the :meth:`push` method.
|
||||||
|
"""
|
||||||
|
|
||||||
def push(self, thing):
|
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:
|
if thing in self:
|
||||||
self.remove(thing)
|
self.remove(thing)
|
||||||
self.append(thing)
|
self.append(thing)
|
||||||
@ -47,8 +57,11 @@ def sharedPrefix(args):
|
|||||||
"""
|
"""
|
||||||
Find the shared prefix between the strings.
|
Find the shared prefix between the strings.
|
||||||
|
|
||||||
For instance, sharedPrefix(['blahblah', 'blahwhat']) is
|
For instance:
|
||||||
'blah'.
|
|
||||||
|
sharedPrefix(['blahblah', 'blahwhat'])
|
||||||
|
|
||||||
|
returns 'blah'.
|
||||||
"""
|
"""
|
||||||
i = 0
|
i = 0
|
||||||
while i < min(map(len, args)):
|
while i < min(map(len, args)):
|
||||||
|
Loading…
Reference in New Issue
Block a user