]> git.mxchange.org Git - quix0rs-apt-p2p.git/blob - krpc.py
added license information
[quix0rs-apt-p2p.git] / krpc.py
1 ## Copyright 2002-2003 Andrew Loewenstern, All Rights Reserved
2 # see LICENSE.txt for license information
3
4 import airhook
5 from twisted.internet.defer import Deferred
6 from twisted.protocols import basic
7 from bencode import bencode, bdecode
8 from twisted.internet import reactor
9 import time
10
11 import hash
12
13 KRPC_TIMEOUT = 60
14
15 KRPC_ERROR = 1
16 KRPC_ERROR_METHOD_UNKNOWN = 2
17 KRPC_ERROR_RECEIVED_UNKNOWN = 3
18 KRPC_ERROR_TIMEOUT = 4
19
20 class KRPC(basic.NetstringReceiver):
21     noisy = 1
22     def __init__(self):
23         self.tids = {}
24
25
26     def dataRecieved(self, data):
27         basic.NetstringReceiver(self, data)
28         if self.brokenPeer:
29             self.resetConnection()
30             
31     def resetConnection(self):
32         self.brokenPeer = 0
33         self._readerState = basic.LENGTH
34         self._readerLength = 0
35
36     def stringReceived(self, str):
37         # bdecode
38         try:
39             msg = bdecode(str)
40         except Exception, e:
41             if self.naisy:
42                 print "response decode error: " + `e`
43             self.d.errback()
44         else:
45             # look at msg type
46             if msg['typ']  == 'req':
47                 ilen = len(str)
48                 # if request
49                 #       tell factory to handle
50                 f = getattr(self.factory ,"krpc_" + msg['req'], None)
51                 if f and callable(f):
52                     msg['arg']['_krpc_sender'] =  self.transport.addr
53                     try:
54                         ret = apply(f, (), msg['arg'])
55                     except Exception, e:
56                         ## send error
57                         out = bencode({'tid':msg['tid'], 'typ':'err', 'err' :`e`})
58                         olen = len(out)
59                         self.sendString(out)
60                     else:
61                         if ret:
62                             #   make response
63                             out = bencode({'tid' : msg['tid'], 'typ' : 'rsp', 'rsp' : ret})
64                         else:
65                             out = bencode({'tid' : msg['tid'], 'typ' : 'rsp', 'rsp' : {}})
66                         #       send response
67                         olen = len(out)
68                         self.sendString(out)
69
70                 else:
71                     if self.noisy:
72                         print "don't know about method %s" % msg['req']
73                     # unknown method
74                     out = bencode({'tid':msg['tid'], 'typ':'err', 'err' : KRPC_ERROR_METHOD_UNKNOWN})
75                     olen = len(out)
76                     self.sendString(out)
77                 if self.noisy:
78                     print "%s %s >>> %s - %s %s %s" % (time.asctime(), self.transport.addr, self.factory.node.port, 
79                                                     ilen, msg['req'], olen)
80             elif msg['typ'] == 'rsp':
81                 # if response
82                 #       lookup tid
83                 if self.tids.has_key(msg['tid']):
84                     df = self.tids[msg['tid']]
85                     #   callback
86                     del(self.tids[msg['tid']])
87                     df.callback({'rsp' : msg['rsp'], '_krpc_sender': self.transport.addr})
88                 else:
89                     print 'timeout ' + `msg['rsp']['sender']`
90                     # no tid, this transaction timed out already...
91             elif msg['typ'] == 'err':
92                 # if error
93                 #       lookup tid
94                 df = self.tids[msg['tid']]
95                 #       callback
96                 df.errback(msg['err'])
97                 del(self.tids[msg['tid']])
98             else:
99                 print "unknown message type " + `msg`
100                 # unknown message type
101                 df = self.tids[msg['tid']]
102                 #       callback
103                 df.errback(KRPC_ERROR_RECEIVED_UNKNOWN)
104                 del(self.tids[msg['tid']])
105                 
106     def sendRequest(self, method, args):
107         # make message
108         # send it
109         msg = {'tid' : hash.newID(), 'typ' : 'req',  'req' : method, 'arg' : args}
110         str = bencode(msg)
111         d = Deferred()
112         self.tids[msg['tid']] = d
113         def timeOut(tids = self.tids, id = msg['tid']):
114             if tids.has_key(id):
115                 df = tids[id]
116                 del(tids[id])
117                 print ">>>>>> KRPC_ERROR_TIMEOUT"
118                 df.errback(KRPC_ERROR_TIMEOUT)
119         reactor.callLater(KRPC_TIMEOUT, timeOut)
120         self.sendString(str)
121         return d
122