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