2 from twisted.internet.defer import Deferred
3 from twisted.protocols import basic
4 from bencode import bencode, bdecode
5 from twisted.internet import reactor
13 KRPC_ERROR_METHOD_UNKNOWN = 2
14 KRPC_ERROR_RECEIVED_UNKNOWN = 3
15 KRPC_ERROR_TIMEOUT = 4
17 class KRPC(basic.NetstringReceiver):
23 def dataRecieved(self, data):
24 basic.NetstringReceiver(self, data)
26 self.resetConnection()
28 def resetConnection(self):
30 self._readerState = basic.LENGTH
31 self._readerLength = 0
33 def stringReceived(self, str):
39 print "response decode error: " + `e`
43 if msg['typ'] == 'req':
46 # tell factory to handle
47 f = getattr(self.factory ,"krpc_" + msg['req'], None)
49 msg['arg']['_krpc_sender'] = self.transport.addr
51 ret = apply(f, (), msg['arg'])
54 out = bencode({'tid':msg['tid'], 'typ':'err', 'err' :`e`})
60 out = bencode({'tid' : msg['tid'], 'typ' : 'rsp', 'rsp' : ret})
62 out = bencode({'tid' : msg['tid'], 'typ' : 'rsp', 'rsp' : {}})
69 print "don't know about method %s" % msg['req']
71 out = bencode({'tid':msg['tid'], 'typ':'err', 'err' : KRPC_ERROR_METHOD_UNKNOWN})
75 print "%s %s >>> %s - %s %s %s" % (time.asctime(), self.transport.addr, self.factory.node.port,
76 ilen, msg['req'], olen)
77 elif msg['typ'] == 'rsp':
80 if self.tids.has_key(msg['tid']):
81 df = self.tids[msg['tid']]
83 del(self.tids[msg['tid']])
84 df.callback({'rsp' : msg['rsp'], '_krpc_sender': self.transport.addr})
86 print 'timeout ' + `msg['rsp']['sender']`
87 # no tid, this transaction timed out already...
88 elif msg['typ'] == 'err':
91 df = self.tids[msg['tid']]
93 df.errback(msg['err'])
94 del(self.tids[msg['tid']])
96 print "unknown message type " + `msg`
97 # unknown message type
98 df = self.tids[msg['tid']]
100 df.errback(KRPC_ERROR_RECEIVED_UNKNOWN)
101 del(self.tids[msg['tid']])
103 def sendRequest(self, method, args):
106 msg = {'tid' : hash.newID(), 'typ' : 'req', 'req' : method, 'arg' : args}
109 self.tids[msg['tid']] = d
110 def timeOut(tids = self.tids, id = msg['tid']):
114 print ">>>>>> KRPC_ERROR_TIMEOUT"
115 df.errback(KRPC_ERROR_TIMEOUT)
116 reactor.callLater(KRPC_TIMEOUT, timeOut)