+ df = self.sendPing(old)
+ df.addErrback(self._staleNodeHandler, old, node, contacted)
+ elif not old and not contacted:
+ # There's room, we just need to contact the node first
+ df = self.sendPing(node)
+ # Also schedule a future ping to make sure the node works
+ def rePing(newnode, self = self):
+ if newnode.id not in self.pinging:
+ self.pinging[newnode.id] = reactor.callLater(self.config['MIN_PING_INTERVAL'],
+ self.sendPing, newnode)
+ return newnode
+ df.addCallback(rePing)
+
+ def _staleNodeHandler(self, err, old, node, contacted):
+ """The pinged node never responded, so replace it."""
+ self.table.invalidateNode(old)
+ self.insertNode(node, contacted)
+ return err
+
+ def nodeFailed(self, node):
+ """Mark a node as having failed a request and schedule a future check.
+
+ @type node: L{node.Node}
+ @param node: the new node to try and insert
+ """
+ exists = self.table.nodeFailed(node)
+
+ # If in the table, schedule a ping, if one isn't already sent/scheduled
+ if exists and node.id not in self.pinging:
+ self.pinging[node.id] = reactor.callLater(self.config['MIN_PING_INTERVAL'],
+ self.sendPing, node)
+
+ def sendPing(self, node):
+ """Ping the node to see if it's still alive.
+
+ @type node: L{node.Node}
+ @param node: the node to send the join to
+ """
+ # Check for a ping already underway
+ if (isinstance(self.pinging.get(node.id, None), DelayedCall) and
+ self.pinging[node.id].active()):
+ self.pinging[node.id].cancel()
+ elif isinstance(self.pinging.get(node.id, None), Deferred):
+ return self.pinging[node.id]
+
+ self.stats.startedAction('ping')
+ df = node.ping(self.node.id)
+ self.pinging[node.id] = df
+ df.addCallbacks(self._pingHandler, self._pingError,
+ callbackArgs = (node, datetime.now()),
+ errbackArgs = (node, datetime.now()))
+ return df
+
+ def _pingHandler(self, dict, node, start):
+ """Node responded properly, update it and return the node object."""
+ self.stats.completedAction('ping', start)
+ del self.pinging[node.id]
+ # Create the node using the returned contact info
+ n = self.Node(dict['id'], dict['_krpc_sender'][0], dict['_krpc_sender'][1])
+ reactor.callLater(0, self.insertNode, n)
+ return n