- """
- insert a node in our local table, pinging oldest contact in bucket, if necessary
-
- If all you have is a host/port, then use addContact, which calls this method after
- receiving the PONG from the remote node. The reason for the seperation is we can't insert
- a node into the table without it's peer-ID. That means of course the node passed into this
- method needs to be a properly formed Node object with a valid ID.
- """
- old = self.table.insertNode(n, contacted=contacted)
- if old and (time.time() - old.lastSeen) > const.MIN_PING_INTERVAL and old.id != self.node.id:
- # the bucket is full, check to see if old node is still around and if so, replace it
-
- ## these are the callbacks used when we ping the oldest node in a bucket
- def _staleNodeHandler(oldnode=old, newnode = n):
- """ called if the pinged node never responds """
- self.table.replaceStaleNode(old, newnode)
-
- def _notStaleNodeHandler(sender, old=old):
- """ called when we get a pong from the old node """
- sender = Node().initWithDict(sender)
- if sender.id == old.id:
- self.table.justSeenNode(old)
-
- df = old.ping(self.node.senderDict())
- df.addCallbacks(_notStaleNodeHandler, _staleNodeHandler)
-
-
- def sendPing(self, node):
- """
- ping a node
- """
- df = node.ping(self.node.senderDict())
- ## these are the callbacks we use when we issue a PING
- def _pongHandler(sender, id=node.id, host=node.host, port=node.port, table=self.table):
- sender, conn = sender
- if id != 20 * ' ' and id != sender['id'].data:
- # whoah, got response from different peer than we were expecting
- pass
- else:
- sender['host'] = host
- sender['port'] = port
- n = Node().initWithDict(sender)
- table.insertNode(n)
- return
- def _defaultPong(err, node=node, table=self.table):
- table.nodeFailed(node)
-
- df.addCallbacks(_pongHandler,_defaultPong)
-
-
- def findCloseNodes(self):
- """
- This does a findNode on the ID one away from our own.
- This will allow us to populate our table with nodes on our network closest to our own.
- This is called as soon as we start up with an empty table
- """
- id = self.node.id[:-1] + chr((ord(self.node.id[-1]) + 1) % 256)
- def callback(nodes):
- pass
- self.findNode(id, callback)
-
- def refreshTable(self):
- """
-
- """
- def callback(nodes):
- pass
-
- for bucket in self.table.buckets:
- if time.time() - bucket.lastAccessed >= const.BUCKET_STALENESS:
- id = newIDInRange(bucket.min, bucket.max)
- self.findNode(id, callback)
-
-
- def retrieveValues(self, key):
- if self.kw.has_key(key):
- c = self.kw.cursor()
- tup = c.set(key)
- l = []
- while(tup and tup[0] == key):
- h1 = tup[1]
- v = loads(self.store[h1])[1]
- l.append(v)
- tup = c.next()
- return l
- return []
-
- #####
- ##### INCOMING MESSAGE HANDLERS
-
- def xmlrpc_ping(self, sender):
- """
- takes sender dict = {'id', <id>, 'port', port} optional keys = 'ip'
- returns sender dict
- """
- ip = self.crequest.getClientIP()
- sender['host'] = ip
- n = Node().initWithDict(sender)
- self.insertNode(n, contacted=0)
- return self.node.senderDict()
-
- def xmlrpc_find_node(self, target, sender):
- nodes = self.table.findNodes(target.data)
- nodes = map(lambda node: node.senderDict(), nodes)
- ip = self.crequest.getClientIP()
- sender['host'] = ip
- n = Node().initWithDict(sender)
- self.insertNode(n, contacted=0)
- return nodes, self.node.senderDict()
-
- def xmlrpc_store_value(self, key, value, sender):
- key = key.data
- h1 = sha(key+value.data).digest()
- t = `time.time()`
- if not self.store.has_key(h1):
- v = dumps((key, value.data, t))
- self.store.put(h1, v)
- self.itime.put(t, h1)
- self.kw.put(key, h1)
- else:
- # update last insert time
- tup = loads(self.store[h1])
- self.store[h1] = dumps((tup[0], tup[1], t))
- self.itime.put(t, h1)
-
- ip = self.crequest.getClientIP()
- sender['host'] = ip
- n = Node().initWithDict(sender)
- self.insertNode(n, contacted=0)
- return self.node.senderDict()
-
- def xmlrpc_find_value(self, key, sender):
- ip = self.crequest.getClientIP()
- key = key.data
- sender['host'] = ip
- n = Node().initWithDict(sender)
- self.insertNode(n, contacted=0)
-
- l = self.retrieveValues(key)
- if len(l) > 0:
- l = map(lambda v: Binary(v), l)
- return {'values' : l}, self.node.senderDict()
- else:
- nodes = self.table.findNodes(key)
- nodes = map(lambda node: node.senderDict(), nodes)
- return {'nodes' : nodes}, self.node.senderDict()
-
-
-
-
-
-#------ testing
-
-def test_build_net(quiet=0, peers=24, host='localhost', pause=1):
- from whrandom import randrange
- import thread
- port = 2001
- l = []