cc175847f3355f06388b25b59e0bae1d92fdf314
[sface.git] / sface / xmlrpcwindow.py
1 import re
2 from lxml import etree
3 from PyQt4.QtXml import QDomDocument
4 from sface.xmlwidget import XmlWindow, DomModel
5
6 class XmlrpcReader():
7     def __init__(self):
8         self.rawOutput = None
9         self.responses = []
10
11     def getAndPrint(self, rawOutput):
12         self.store(rawOutput)
13         self.extractXml()
14         self.xmlrpcWindow.setData(self.xml)
15         if self.xml != "<debug></debug>":
16             # only popup the window if we have something to show
17             self.showXmlrpc()
18
19     def store(self, rawOutput):
20         self.rawOutput = rawOutput
21
22     def parseMethodResponse(self, mr):
23         tree = etree.fromstring(str(mr))
24
25         response = {"kind": "unknown"}
26
27         if tree.tag != "methodResponse" or (len(list(tree))==0):
28             return response
29
30         # a fault should look like:
31         #     kind: "fault"
32         #     faultCode: "102"
33         #     faultString: "Register: Missing authority..."
34
35         faults = tree.xpath("//methodResponse/fault")
36         for fault in faults:
37             response["kind"] = "fault"
38             structs = fault.xpath("value/struct")
39             for struct in structs:
40                 members = struct.xpath("member")
41                 for member in members:
42                     names = member.xpath("name")
43                     values = member.xpath("value")
44                     if (names) and (values):
45                         name = names[0]
46                         value = values[0]
47                         if len(list(value))>0:
48                             data = list(value)[0]
49                             response[name.text] = data.text
50             # once we have the first fault, return
51             return response
52
53         # whatever didn't fault must have succeeded?
54         response["kind"] = "success"
55
56         return response
57
58     def extractXml(self):
59         pttrnAsk = '<methodCall>.*?</methodCall>'
60         pttrnAns = '<methodResponse>.*?</methodResponse>'
61         answers = re.compile(pttrnAsk, re.DOTALL).findall(self.rawOutput)
62         replies = re.compile(pttrnAns, re.DOTALL).findall(self.rawOutput)
63         # cleaning
64         answers = [ x.replace('\\n','\n') for x in answers ]
65         replies = [ x.replace('\\n','\n').replace("'\nbody: '", '') for x in replies ]
66         replies.reverse() # so that I use pop() as popleft
67         # A well-formed XML document must have one, and only one, top-level element
68
69         self.responses = []
70
71         self.xml = ""
72         for ans in answers:
73             self.xml += ans
74             # we could have less responses than calls, so guard the pop
75             if replies:
76                 replyXml = replies.pop()
77                 self.xml += replyXml
78                 self.responses.append(self.parseMethodResponse(replyXml))
79
80         # just in case somehow we ended up with more responses than calls
81         while replies:
82             replyXml = replies.pop()
83             self.xml += replyXml
84             self.responses.append(self.parseMethodResponse(replyXml))
85
86         return self.xml
87
88     def stats(self):
89         # statistics: round-trip time, size of the com
90         pass
91
92 class XmlrpcTracker(XmlrpcReader):
93     def __init__(self):
94         XmlrpcReader.__init__(self)
95         self.xmlrpcWindow = XmlrpcWindow()
96
97     def getAndPrint(self, rawOutput):
98         self.store(rawOutput)
99         self.extractXml()
100         self.xmlrpcWindow.setData(self.xml)
101         if self.xml != "<debug></debug>":
102             # only popup the window if we have something to show
103             self.showXmlrpc()
104
105     def showXmlrpc(self):
106         self.xmlrpcWindow.show()
107         self.xmlrpcWindow.resize(500, 640)
108         self.xmlrpcWindow.raise_()
109         self.xmlrpcWindow.activateWindow()
110
111     def extractXml(self):
112         self.xml = "<debug>" + XmlrpcReader.extractXml(self) + "</debug>"
113
114 class XmlrpcWindow(XmlWindow):
115     def __init__(self, parent=None):
116         # super __init__() calls updateView,
117         # which assumes you have some data
118         self.data = '<debug/>'
119         XmlWindow.__init__(self, parent, 'XMLRPC window')
120
121     def setData(self, XmlrpcCom):
122         self.data = XmlrpcCom
123
124     def updateView(self):
125         XmlWindow.updateView(self)
126
127         self.document.setContent(self.data)