E5Network/E5XmlRpcClient.py

changeset 4258
d141e2bb94cc
child 4326
e52318f11812
equal deleted inserted replaced
4256:5c61205c4bd7 4258:d141e2bb94cc
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a xmlrpc client for Qt.
8 """
9
10 from __future__ import unicode_literals
11 try:
12 import xmlrpclib as xmlrpc
13 except ImportError:
14 import xmlrpc.client as xmlrpc
15
16 from PyQt5.QtCore import QObject, QUrl, QByteArray
17 from PyQt5.QtNetwork import QNetworkAccessManager, \
18 QNetworkRequest, QNetworkReply
19
20 from E5Network.E5NetworkProxyFactory import proxyAuthenticationRequired
21 try:
22 from E5Network.E5SslErrorHandler import E5SslErrorHandler
23 SSL_AVAILABLE = True
24 except ImportError:
25 SSL_AVAILABLE = False
26
27
28 class E5XmlRpcClient(QObject):
29 """
30 Class implementing a xmlrpc client for Qt.
31 """
32 def __init__(self, url, parent=None):
33 """
34 Constructor
35
36 @param url xmlrpc handler URL (string or QUrl)
37 @param parent parent object (QObject)
38 """
39 super(E5XmlRpcClient, self).__init__(parent)
40
41 # attributes for the network objects
42 self.__networkManager = QNetworkAccessManager(self)
43 self.__networkManager.proxyAuthenticationRequired.connect(
44 proxyAuthenticationRequired)
45 self.__networkManager.finished.connect(self.__replyFinished)
46 if SSL_AVAILABLE:
47 self.__sslErrorHandler = E5SslErrorHandler(self)
48 self.__networkManager.sslErrors.connect(self.__sslErrors)
49
50 self.__callmap = {}
51
52 self.__request = QNetworkRequest(QUrl(url))
53 self.__request.setRawHeader("User-Agent", "E5XmlRpcClient/1.0")
54 self.__request.setHeader(QNetworkRequest.ContentTypeHeader, "text/xml")
55
56 def setUrl(self, url):
57 """
58 Public slot to set the xmlrpc handler URL.
59
60 @param url xmlrpc handler URL (string or QUrl)
61 """
62 url = QUrl(url)
63 if url.isValid():
64 self.__request.setUrl(url)
65
66 def call(self, method, args, responseCallback, errorCallback):
67 """
68 Public method to call the remote server.
69
70 @param method name of the remote method to be called (string)
71 @param args tuple of method arguments (tuple)
72 @param responseCallback method to be called with the returned
73 result as a tuple (function)
74 @param errorCallback method to be called in case of an error
75 with error code and error string (function)
76 """
77 assert isinstance(args, tuple), \
78 "argument must be tuple or Fault instance"
79
80 data = xmlrpc.dumps(args, method).encode("utf-8")
81 reply = self.__networkManager.post(
82 self.__request, QByteArray(data))
83 self.__callmap[reply] = (responseCallback, errorCallback)
84
85 def abort(self):
86 """
87 Public method to abort all calls.
88 """
89 for reply in list(self.__callmap):
90 if reply.isRunning():
91 reply.abort()
92
93 def __sslErrors(self, reply, errors):
94 """
95 Private slot to handle SSL errors.
96
97 @param reply reference to the reply object (QNetworkReply)
98 @param errors list of SSL errors (list of QSslError)
99 """
100 ignored = self.__sslErrorHandler.sslErrorsReply(reply, errors)[0]
101 if ignored == E5SslErrorHandler.NotIgnored and reply in self.__callmap:
102 self.__callmap[reply][1](xmlrpc.TRANSPORT_ERROR, self.tr(
103 "SSL Error"))
104
105 def __replyFinished(self, reply):
106 """
107 Private slot handling the receipt of a reply.
108
109 @param reply reference to the finished reply (QNetworkReply)
110 """
111 if reply not in self.__callmap:
112 return
113
114 if reply.error() != QNetworkReply.NoError:
115 self.__callmap[reply][1](xmlrpc.TRANSPORT_ERROR,
116 reply.errorString())
117 else:
118 data = bytes(reply.readAll()).decode("utf-8")
119 try:
120 data = xmlrpc.loads(data)[0]
121 self.__callmap[reply][0](data)
122 except xmlrpc.Fault as fault:
123 self.__callmap[reply][1](fault.faultCode, fault.faultString)
124
125 reply.deleteLater()
126 del self.__callmap[reply]

eric ide

mercurial