WIP on final version of accepted INFOCOM paper.
[quix0rs-apt-p2p.git] / apt_p2p_Khashmir / knode.py
1
2 """Represents a khashmir node in the DHT."""
3
4 from twisted.python import log
5
6 from node import Node, NULL_ID
7
8 class KNodeError(Exception):
9     """An error occurred in contacting the node."""
10
11 class KNodeBase(Node):
12     """A basic node that can only be pinged and help find other nodes."""
13     
14     def checkSender(self, dict):
15         """Check the sender's info to make sure it meets expectations."""
16         try:
17             senderid = dict['id']
18         except KeyError:
19             log.msg("No peer id in response")
20             raise KNodeError, "No peer id in response."
21         else:
22             if self.id != NULL_ID and senderid != self.id:
23                 log.msg("Got response from different node than expected.")
24                 self.table.invalidateNode(self)
25                 raise KNodeError, "Node ID has changed"
26                 
27         return dict
28
29     def ping(self, id):
30         """Ping the node."""
31         df = self.conn.sendRequest('ping', {"id":id})
32         df.addCallback(self.checkSender)
33         return df
34     
35     def join(self, id):
36         """Use the node to bootstrap into the system."""
37         df = self.conn.sendRequest('join', {"id":id})
38         df.addCallback(self.checkSender)
39         return df
40     
41     def find_node(self, id, target):
42         """Request the nearest nodes to the target that the node knows about."""
43         df = self.conn.sendRequest('find_node', {"target" : target, "id": id})
44         df.addCallback(self.checkSender)
45         return df
46
47 class KNodeRead(KNodeBase):
48     """More advanced node that can also find and send values."""
49     
50     def find_value(self, id, key):
51         """Request the nearest nodes to the key that the node knows about."""
52         df =  self.conn.sendRequest('find_value', {"key" : key, "id" : id})
53         df.addCallback(self.checkSender)
54         return df
55
56     def get_value(self, id, key, num):
57         """Request the values that the node has for the key."""
58         df = self.conn.sendRequest('get_value', {"key" : key, "num": num, "id" : id})
59         df.addCallback(self.checkSender)
60         return df
61
62 class KNodeWrite(KNodeRead):
63     """Most advanced node that can also store values."""
64     
65     def store_value(self, id, key, value, token):
66         """Store a value in the node."""
67         df = self.conn.sendRequest('store_value', {"key" : key, "value" : value, "token" : token, "id": id})
68         df.addCallback(self.checkSender)
69         return df