WebBrowser/SafeBrowsing/SafeBrowsingAPIClient.py

branch
safe_browsing
changeset 5809
5b53c17b7d93
child 5811
5358a3c7995f
equal deleted inserted replaced
5808:7bf90dcae4e1 5809:5b53c17b7d93
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the low level interface for Google Safe Browsing.
8 """
9
10 from __future__ import unicode_literals
11 try:
12 str = unicode # __IGNORE_EXCEPTION__
13 except NameError:
14 pass
15
16 import json
17 import random
18
19 from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject, QDateTime, QTimer, \
20 QUrl
21 from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
22
23 from WebBrowser.WebBrowserWindow import WebBrowserWindow
24
25
26 class SafeBrowsingAPIClient(QObject):
27 """
28 Class implementing the low level interface for Google Safe Browsing.
29 """
30 ClientId = "eric6_API_client"
31 ClientVersion = "1.0.0"
32
33 GsbUrlTemplate = "https://safebrowsing.googleapis.com/v4/{0}?key={1}"
34
35 networkError = pyqtSignal(str)
36 threatLists = pyqtSignal(list)
37
38 # threatListUpdates:fetch Content-Type: application/json POST
39 # fullHashes:find Content-Type: application/json POST
40
41 def __init__(self, apiKey, fairUse=True, parent=None):
42 """
43 Constructor
44
45 @param apiKey API key to be used
46 @type str
47 @param fairUse flag indicating to follow the fair use policy
48 @type bool
49 @param parent reference to the parent object
50 @type QObject
51 """
52 self.__apiKey = apiKey
53 self.__fairUse = fairUse
54
55 self.__nextRequestNoSoonerThan = QDateTime()
56 self.__replies = []
57 self.__failCount = 0
58
59 def getThreatLists(self):
60 """
61 Public method to retrieve all available threat lists.
62
63 @return threat lists
64 @rtype list of dictionaries
65 """
66 url = QUrl(self.GsbUrlTemplate.format("threatLists", self.__apiKey))
67 req = QNetworkRequest(url)
68 reply = WebBrowserWindow.networkManager().get(req)
69 reply.finished.connect(self.__threatListsReceived)
70
71 @pyqtSlot()
72 def __threatListsReceived(self):
73 """
74 Private slot handling the threat lists.
75 """
76 reply = self.sender()
77 result, hasError = self.__extractData(reply)
78 if hasError:
79 # reschedule
80 self.networkError.emit(reply.errorString())
81 self.__reschedule(reply.error(), self.getThreatLists)
82 else:
83 self.__setWaitDuration(result.get("minimumWaitDuration"))
84 self.threatLists.emit(result["threatLists"])
85 self.__failCount = 0
86
87 if reply in self.__replies:
88 self.__replies.remove(reply)
89 reply.deleteLater()
90
91 def __extractData(self, reply):
92 """
93 Private method to extract the data of a network reply.
94
95 @param reply reference to the network reply object
96 @type QNetworkReply
97 @return tuple containing the extracted data and an error flag
98 @type tuple of (list or dict, bool)
99 """
100 if reply.error() != QNetworkReply.NoError:
101 return None, True
102
103 result = json.loads(str(reply.readAll(), "utf-8"))
104 return result, False
105
106 def __setWaitDuration(self, minimumWaitDuration):
107 """
108 Private method to set the minimum wait duration.
109
110 @param minimumWaitDuration duration to be set
111 @type str
112 """
113 if not self.__fairUse or minimumWaitDuration is None:
114 self.__nextRequestNoSoonerThan = QDateTime()
115 else:
116 waitDuration = int(minimumWaitDuration.rstrip("s"))
117 self.__nextRequestNoSoonerThan = \
118 QDateTime.currentDateTime().addSecs(waitDuration)
119
120 def __reschedule(self, errorCode, func):
121 """
122 Private method to reschedule an API access.
123
124 @param errorCode error code returned by the function to be rescheduled
125 @type int
126 @param func function to be rescheduled
127 @type func
128 """
129 if errorCode >= 500:
130 return
131
132 self.__failCount += 1
133 waitDuration = min(
134 int(2 ** (self.__failCount - 1) * 15 * 60 * (1 + random.random())),
135 24 * 60 * 60)
136 QTimer.singleShot(waitDuration * 1000, func)

eric ide

mercurial