updated api

This commit is contained in:
Brian Muller 2014-01-13 19:49:16 -05:00
parent ee0c6b9bd5
commit 9e8d239d73
6 changed files with 48 additions and 27 deletions

View File

@ -86,7 +86,6 @@ class SpiderCrawl(object):
""" """
Handle the result of an iteration in C{_find}. Handle the result of an iteration in C{_find}.
""" """
print "got some responses: ", responses
toremove = [] toremove = []
for peerid, response in responses.items(): for peerid, response in responses.items():
# response will be a tuple of (<response received>, <value>) # response will be a tuple of (<response received>, <value>)
@ -113,7 +112,7 @@ class Server(object):
to start listening as an active node on the network. 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. Create a server instance. This will start listening on the given port.
@ -125,11 +124,17 @@ class Server(object):
self.alpha = alpha self.alpha = alpha
self.log = Logger(system=self) self.log = Logger(system=self)
storage = ForgetfulStorage() 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.protocol = KademliaProtocol(self.node.id, storage, ksize)
self.refreshLoop = LoopingCall(self.refreshTable).start(3600) self.refreshLoop = LoopingCall(self.refreshTable).start(3600)
def listen(self, port): 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) return reactor.listenUDP(port, self.protocol)
def refreshTable(self): def refreshTable(self):
@ -139,12 +144,24 @@ class Server(object):
""" """
ds = [] ds = []
for id in self.protocol.getRefreshIDs(): for id in self.protocol.getRefreshIDs():
node = Node(None, None, id) node = Node(id)
nearest = self.protocol.router.findNeighbors(node, self.alpha) nearest = self.protocol.router.findNeighbors(node, self.alpha)
spider = SpiderCrawl(self.protocol, node, nearest) spider = SpiderCrawl(self.protocol, node, nearest)
ds.append(spider.findNodes()) ds.append(spider.findNodes())
return defer.gatherResults(ds) 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): def bootstrap(self, addrs):
""" """
Bootstrap the server by connecting to other known nodes in the network. Bootstrap the server by connecting to other known nodes in the network.
@ -155,7 +172,7 @@ class Server(object):
nodes = [] nodes = []
for addr, result in results.items(): for addr, result in results.items():
if result[0]: 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) spider = SpiderCrawl(self.protocol, self.node, nodes, self.ksize, self.alpha)
return spider.findNodes() return spider.findNodes()
@ -170,7 +187,7 @@ class Server(object):
@return: C{None} if not found, the value otherwise. @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) 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.findValue() return spider.findValue()
@ -189,7 +206,7 @@ class Server(object):
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.gatherResults(ds)
node = Node(None, None, 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)

View File

@ -3,10 +3,10 @@ import heapq
class Node: class Node:
def __init__(self, ip, port, id): def __init__(self, id, ip=None, port=None):
self.id = id
self.ip = ip self.ip = ip
self.port = port self.port = port
self.id = id
self.long_id = long(id.encode('hex'), 16) self.long_id = long(id.encode('hex'), 16)
def sameHomeAs(self, node): def sameHomeAs(self, node):
@ -22,7 +22,7 @@ class Node:
return iter([self.ip, self.port, self.id]) return iter([self.ip, self.port, self.id])
def __repr__(self): def __repr__(self):
return repr([self.ip, self.port, self.long_id]) return repr([self.long_id, self.ip, self.port])
def __str__(self): def __str__(self):
return "%s:%s" % (self.ip, str(self.port)) return "%s:%s" % (self.ip, str(self.port))

View File

@ -24,25 +24,25 @@ class KademliaProtocol(RPCProtocol):
return ids return ids
def rpc_ping(self, sender, nodeid): def rpc_ping(self, sender, nodeid):
source = Node(sender[0], sender[1], nodeid) source = Node(nodeid, sender[0], sender[1])
self.router.addContact(source) self.router.addContact(source)
return self.sourceID return self.sourceID
def rpc_store(self, sender, nodeid, key, value): 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.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
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))
source = Node(sender[0], sender[1], nodeid) source = Node(nodeid, sender[0], sender[1])
self.router.addContact(source) self.router.addContact(source)
node = Node(None, None, key) node = Node(key)
return map(tuple, self.router.findNeighbors(node, exclude=source)) return map(tuple, self.router.findNeighbors(node, exclude=source))
def rpc_find_value(self, sender, nodeid, key): 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) self.router.addContact(source)
value = self.storage.get(key, None) value = self.storage.get(key, None)
if value is None: if value is None:

View File

@ -11,7 +11,7 @@ from kademlia.tests.utils import mknode
class NodeTest(unittest.TestCase): class NodeTest(unittest.TestCase):
def test_longID(self): def test_longID(self):
rid = hashlib.sha1(str(random.getrandbits(255))).digest() 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)) self.assertEqual(n.long_id, long(rid.encode('hex'), 16))
def test_distanceCalculation(self): def test_distanceCalculation(self):
@ -19,8 +19,8 @@ class NodeTest(unittest.TestCase):
ridtwo = hashlib.sha1(str(random.getrandbits(255))) ridtwo = hashlib.sha1(str(random.getrandbits(255)))
shouldbe = long(ridone.hexdigest(), 16) ^ long(ridtwo.hexdigest(), 16) shouldbe = long(ridone.hexdigest(), 16) ^ long(ridtwo.hexdigest(), 16)
none = Node(None, None, ridone.digest()) none = Node(ridone.digest())
ntwo = Node(None, None, ridtwo.digest()) ntwo = Node(ridtwo.digest())
self.assertEqual(none.distanceTo(ntwo), shouldbe) self.assertEqual(none.distanceTo(ntwo), shouldbe)
@ -37,7 +37,7 @@ class NodeHeapTest(unittest.TestCase):
def test_iteration(self): def test_iteration(self):
heap = NodeHeap(5) 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): for index, node in enumerate(nodes):
heap.push(index, node) heap.push(index, node)
for index, node in enumerate(heap): for index, node in enumerate(heap):
@ -46,7 +46,7 @@ class NodeHeapTest(unittest.TestCase):
def test_remove(self): def test_remove(self):
heap = NodeHeap(5) 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): for index, node in enumerate(nodes):
heap.push(index, node) heap.push(index, node)

View File

@ -9,14 +9,14 @@ from kademlia.node import Node
from kademlia.routing import RoutingTable 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. Make a node. Created a random id if not specified.
""" """
if intid is not None: if intid is not None:
id = pack('>l', intid) id = pack('>l', intid)
id = id or hashlib.sha1(str(random.getrandbits(255))).digest() id = id or hashlib.sha1(str(random.getrandbits(255))).digest()
return Node(ip, port, id) return Node(id, ip, port)
class FakeProtocol(object): class FakeProtocol(object):
@ -35,25 +35,25 @@ class FakeProtocol(object):
return ids return ids
def rpc_ping(self, sender, nodeid): def rpc_ping(self, sender, nodeid):
source = Node(sender[0], sender[1], nodeid) source = Node(nodeid, sender[0], sender[1])
self.router.addContact(source) self.router.addContact(source)
return self.sourceID return self.sourceID
def rpc_store(self, sender, nodeid, key, value): 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.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
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))
source = Node(sender[0], sender[1], nodeid) source = Node(nodeid, sender[0], sender[1])
self.router.addContact(source) self.router.addContact(source)
node = Node(None, None, key) node = Node(key)
return map(tuple, self.router.findNeighbors(node, exclude=source)) return map(tuple, self.router.findNeighbors(node, exclude=source))
def rpc_find_value(self, sender, nodeid, key): 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) self.router.addContact(source)
value = self.storage.get(key, None) value = self.storage.get(key, None)
if value is None: if value is None:

View File

@ -1,9 +1,13 @@
from twisted.application import service, internet from twisted.application import service, internet
from twisted.python.log import ILogObserver
import sys, os import sys, os
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))
from kademlia.network import Server from kademlia.network import Server
from kademlia import log
application = service.Application("kademlia") application = service.Application("kademlia")
application.setComponent(ILogObserver, log.FileLogObserver(sys.stdout, log.INFO).emit)
kserver = Server() kserver = Server()
server = internet.UDPServer(1234, kserver.protocol) server = internet.UDPServer(1234, kserver.protocol)
server.setServiceParent(application) server.setServiceParent(application)