create XmlrpcReader class for parsing xmlrpc response faults, split from debug window...
[sface.git] / sface / xmlrpcwindow.py
index a368a77..cc17584 100644 (file)
@@ -1,10 +1,12 @@
 import re
+from lxml import etree
 from PyQt4.QtXml import QDomDocument
 from sface.xmlwidget import XmlWindow, DomModel
 
-class XmlrpcTracker():
+class XmlrpcReader():
     def __init__(self):
-        self.xmlrpcWindow = XmlrpcWindow()
+        self.rawOutput = None
+        self.responses = []
 
     def getAndPrint(self, rawOutput):
         self.store(rawOutput)
@@ -14,15 +16,45 @@ class XmlrpcTracker():
             # only popup the window if we have something to show
             self.showXmlrpc()
 
-    def showXmlrpc(self):
-        self.xmlrpcWindow.show()
-        self.xmlrpcWindow.resize(500, 640)
-        self.xmlrpcWindow.raise_()
-        self.xmlrpcWindow.activateWindow()
-
     def store(self, rawOutput):
         self.rawOutput = rawOutput
 
+    def parseMethodResponse(self, mr):
+        tree = etree.fromstring(str(mr))
+
+        response = {"kind": "unknown"}
+
+        if tree.tag != "methodResponse" or (len(list(tree))==0):
+            return response
+
+        # a fault should look like:
+        #     kind: "fault"
+        #     faultCode: "102"
+        #     faultString: "Register: Missing authority..."
+
+        faults = tree.xpath("//methodResponse/fault")
+        for fault in faults:
+            response["kind"] = "fault"
+            structs = fault.xpath("value/struct")
+            for struct in structs:
+                members = struct.xpath("member")
+                for member in members:
+                    names = member.xpath("name")
+                    values = member.xpath("value")
+                    if (names) and (values):
+                        name = names[0]
+                        value = values[0]
+                        if len(list(value))>0:
+                            data = list(value)[0]
+                            response[name.text] = data.text
+            # once we have the first fault, return
+            return response
+
+        # whatever didn't fault must have succeeded?
+        response["kind"] = "success"
+
+        return response
+
     def extractXml(self):
         pttrnAsk = '<methodCall>.*?</methodCall>'
         pttrnAns = '<methodResponse>.*?</methodResponse>'
@@ -33,15 +65,52 @@ class XmlrpcTracker():
         replies = [ x.replace('\\n','\n').replace("'\nbody: '", '') for x in replies ]
         replies.reverse() # so that I use pop() as popleft
         # A well-formed XML document must have one, and only one, top-level element
-        self.xml = '<debug>'
+
+        self.responses = []
+
+        self.xml = ""
         for ans in answers:
-            self.xml += ans + replies.pop()
-        self.xml += '</debug>'
+            self.xml += ans
+            # we could have less responses than calls, so guard the pop
+            if replies:
+                replyXml = replies.pop()
+                self.xml += replyXml
+                self.responses.append(self.parseMethodResponse(replyXml))
+
+        # just in case somehow we ended up with more responses than calls
+        while replies:
+            replyXml = replies.pop()
+            self.xml += replyXml
+            self.responses.append(self.parseMethodResponse(replyXml))
+
+        return self.xml
 
     def stats(self):
         # statistics: round-trip time, size of the com
         pass
 
+class XmlrpcTracker(XmlrpcReader):
+    def __init__(self):
+        XmlrpcReader.__init__(self)
+        self.xmlrpcWindow = XmlrpcWindow()
+
+    def getAndPrint(self, rawOutput):
+        self.store(rawOutput)
+        self.extractXml()
+        self.xmlrpcWindow.setData(self.xml)
+        if self.xml != "<debug></debug>":
+            # only popup the window if we have something to show
+            self.showXmlrpc()
+
+    def showXmlrpc(self):
+        self.xmlrpcWindow.show()
+        self.xmlrpcWindow.resize(500, 640)
+        self.xmlrpcWindow.raise_()
+        self.xmlrpcWindow.activateWindow()
+
+    def extractXml(self):
+        self.xml = "<debug>" + XmlrpcReader.extractXml(self) + "</debug>"
+
 class XmlrpcWindow(XmlWindow):
     def __init__(self, parent=None):
         # super __init__() calls updateView,