1 ## Copyright 2002-2003 Andrew Loewenstern, All Rights Reserved
2 # see LICENSE.txt for license information
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
16 KRPC_ERROR_METHOD_UNKNOWN = 2
17 KRPC_ERROR_RECEIVED_UNKNOWN = 3
18 KRPC_ERROR_TIMEOUT = 4
20 class KRPC(basic.NetstringReceiver):
26 def dataRecieved(self, data):
27 basic.NetstringReceiver(self, data)
29 self.resetConnection()
31 def resetConnection(self):
33 self._readerState = basic.LENGTH
34 self._readerLength = 0
36 def stringReceived(self, str):
42 print "response decode error: " + `e`
46 if msg['typ'] == 'req':
49 # tell factory to handle
50 f = getattr(self.factory ,"krpc_" + msg['req'], None)
52 msg['arg']['_krpc_sender'] = self.transport.addr
54 ret = apply(f, (), msg['arg'])
57 out = bencode({'tid':msg['tid'], 'typ':'err', 'err' :`e`})
63 out = bencode({'tid' : msg['tid'], 'typ' : 'rsp', 'rsp' : ret})
65 out = bencode({'tid' : msg['tid'], 'typ' : 'rsp', 'rsp' : {}})
72 print "don't know about method %s" % msg['req']
74 out = bencode({'tid':msg['tid'], 'typ':'err', 'err' : KRPC_ERROR_METHOD_UNKNOWN})
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':
83 if self.tids.has_key(msg['tid']):
84 df = self.tids[msg['tid']]
86 del(self.tids[msg['tid']])
87 df.callback({'rsp' : msg['rsp'], '_krpc_sender': self.transport.addr})
89 print 'timeout ' + `msg['rsp']['sender']`
90 # no tid, this transaction timed out already...
91 elif msg['typ'] == 'err':
94 df = self.tids[msg['tid']]
96 df.errback(msg['err'])
97 del(self.tids[msg['tid']])
99 print "unknown message type " + `msg`
100 # unknown message type
101 df = self.tids[msg['tid']]
103 df.errback(KRPC_ERROR_RECEIVED_UNKNOWN)
104 del(self.tids[msg['tid']])
106 def sendRequest(self, method, args):
109 msg = {'tid' : hash.newID(), 'typ' : 'req', 'req' : method, 'arg' : args}
112 self.tids[msg['tid']] = d
113 def timeOut(tids = self.tids, id = msg['tid']):
117 print ">>>>>> KRPC_ERROR_TIMEOUT"
118 df.errback(KRPC_ERROR_TIMEOUT)
119 reactor.callLater(KRPC_TIMEOUT, timeOut)