]> git.mxchange.org Git - quix0rs-apt-p2p.git/blobdiff - krpc.py
ripped out xmlrpc, experimented with xmlrpc but with bencode, finally
[quix0rs-apt-p2p.git] / krpc.py
diff --git a/krpc.py b/krpc.py
new file mode 100644 (file)
index 0000000..8569bbf
--- /dev/null
+++ b/krpc.py
@@ -0,0 +1,101 @@
+import airhook
+from twisted.internet.defer import Deferred
+from twisted.protocols import basic
+from bencode import bencode, bdecode
+from twisted.internet import reactor
+
+import hash
+
+KRPC_TIMEOUT = 30
+
+KRPC_ERROR = 1
+KRPC_ERROR_METHOD_UNKNOWN = 2
+KRPC_ERROR_RECEIVED_UNKNOWN = 3
+KRPC_ERROR_TIMEOUT = 4
+
+class KRPC(basic.NetstringReceiver):
+    noisy = 1
+    def __init__(self):
+        self.tids = {}
+
+    def stringReceived(self, str):
+        # bdecode
+        try:
+            msg = bdecode(str)
+        except Exception, e:
+            print "response decode error: " + `e`
+            self.d.errback()
+        else:
+            # look at msg type
+            if msg['typ']  == 'req':
+                ilen = len(str)
+                # if request
+                #      tell factory to handle
+                f = getattr(self.factory ,"krpc_" + msg['req'], None)
+                if f and callable(f):
+                    msg['arg']['_krpc_sender'] =  self.transport.addr
+                    try:
+                        ret = apply(f, (), msg['arg'])
+                    except Exception, e:
+                        ## send error
+                        str = bencode({'tid':msg['tid'], 'typ':'err', 'err' :`e`})
+                        olen = len(str)
+                        self.sendString(str)
+                    else:
+                        if ret:
+                            #  make response
+                            str = bencode({'tid' : msg['tid'], 'typ' : 'rsp', 'rsp' : ret})
+                        else:
+                            str = bencode({'tid' : msg['tid'], 'typ' : 'rsp', 'rsp' : []})
+                        #      send response
+                        olen = len(str)
+                        self.sendString(str)
+
+                else:
+                    # unknown method
+                    str = bencode({'tid':msg['tid'], 'typ':'err', 'err' : KRPC_ERROR_METHOD_UNKNOWN})
+                    olen = len(str)
+                    self.sendString(str)
+                if self.noisy:
+                    print "%s >>> (%s, %s) - %s %s %s" % (self.transport.addr, self.factory.node.host, self.factory.node.port, 
+                                                    ilen, msg['req'], olen)
+            elif msg['typ'] == 'rsp':
+                # if response
+                #      lookup tid
+                if self.tids.has_key(msg['tid']):
+                    df = self.tids[msg['tid']]
+                    #  callback
+                    df.callback(msg['rsp'])
+                    del(self.tids[msg['tid']])
+                # no tid, perhaps this transaction timed out already...
+            elif msg['typ'] == 'err':
+                # if error
+                #      lookup tid
+                df = self.tids[msg['tid']]
+                #      callback
+                df.errback(msg['err'])
+                del(self.tids[msg['tid']])
+            else:
+                # unknown message type
+                df = self.tids[msg['tid']]
+                #      callback
+                df.errback(KRPC_ERROR_RECEIVED_UNKNOWN)
+                del(self.tids[msg['tid']])
+                
+    def sendRequest(self, method, args):
+        # make message
+        # send it
+        msg = {'tid' : hash.newID(), 'typ' : 'req',  'req' : method, 'arg' : args}
+        str = bencode(msg)
+        self.sendString(str)
+        d = Deferred()
+        self.tids[msg['tid']] = d
+        
+        def timeOut(tids = self.tids, id = msg['tid']):
+            if tids.has_key(id):
+                df = tids[id]
+                del(tids[id])
+                df.errback(KRPC_ERROR_TIMEOUT)
+        reactor.callLater(KRPC_TIMEOUT, timeOut)
+        return d
\ No newline at end of file