8
8
GCM_URL = 'https://android.googleapis.com/gcm/send'
9
9
10
10
11
- class GCMException (Exception ): pass
12
- class GCMMalformedJsonException (GCMException ): pass
13
- class GCMConnectionException (GCMException ): pass
14
- class GCMAuthenticationException (GCMException ): pass
15
- class GCMTooManyRegIdsException (GCMException ): pass
16
- class GCMInvalidTtlException (GCMException ): pass
11
+ class GCMException (Exception ):
12
+ pass
13
+
14
+
15
+ class GCMMalformedJsonException (GCMException ):
16
+ pass
17
+
18
+
19
+ class GCMConnectionException (GCMException ):
20
+ pass
21
+
22
+
23
+ class GCMAuthenticationException (GCMException ):
24
+ pass
25
+
26
+
27
+ class GCMTooManyRegIdsException (GCMException ):
28
+ pass
29
+
30
+
31
+ class GCMInvalidTtlException (GCMException ):
32
+ pass
17
33
18
34
# Exceptions from Google responses
19
- class GCMMissingRegistrationException (GCMException ): pass
20
- class GCMMismatchSenderIdException (GCMException ): pass
21
- class GCMNotRegisteredException (GCMException ): pass
22
- class GCMMessageTooBigException (GCMException ): pass
23
- class GCMInvalidRegistrationException (GCMException ): pass
24
- class GCMUnavailableException (GCMException ): pass
35
+
36
+
37
+ class GCMMissingRegistrationException (GCMException ):
38
+ pass
39
+
40
+
41
+ class GCMMismatchSenderIdException (GCMException ):
42
+ pass
43
+
44
+
45
+ class GCMNotRegisteredException (GCMException ):
46
+ pass
47
+
48
+
49
+ class GCMMessageTooBigException (GCMException ):
50
+ pass
51
+
52
+
53
+ class GCMInvalidRegistrationException (GCMException ):
54
+ pass
55
+
56
+
57
+ class GCMUnavailableException (GCMException ):
58
+ pass
25
59
26
60
27
61
# TODO: Refactor this to be more human-readable
28
62
def group_response (response , registration_ids , key ):
29
63
# Pair up results and reg_ids
30
64
mapping = zip (registration_ids , response ['results' ])
31
65
# Filter by key
32
- filtered = filter (lambda x : key in x [1 ], mapping )
33
- # Only consider the value in the dict
34
- tupled = [(s [0 ], s [1 ][key ]) for s in filtered ]
66
+ filtered = ((reg_id , res [key ]) for reg_id , res in mapping if key in res )
35
67
# Grouping of errors and mapping of ids
36
68
if key is 'registration_id' :
37
- grouping = {}
38
- for k , v in tupled :
39
- grouping [k ] = v
69
+ grouping = dict (filtered )
40
70
else :
41
71
grouping = defaultdict (list )
42
- for k , v in tupled :
72
+ for k , v in filtered :
43
73
grouping [v ].append (k )
44
74
45
- if len (grouping ) == 0 :
46
- return
47
- return grouping
75
+ return grouping or None
48
76
49
77
50
78
def urlencode_utf8 (params ):
@@ -56,7 +84,7 @@ def urlencode_utf8(params):
56
84
if hasattr (params , 'items' ):
57
85
params = params .items ()
58
86
59
- params = (
87
+ params = (
60
88
'=' .join ((
61
89
urllib .quote_plus (k .encode ('utf8' ), safe = '/' ),
62
90
urllib .quote_plus (v .encode ('utf8' ), safe = '/' )
@@ -69,8 +97,8 @@ def urlencode_utf8(params):
69
97
class GCM (object ):
70
98
71
99
# Timeunit is milliseconds.
72
- BACKOFF_INITIAL_DELAY = 1000 ;
73
- MAX_BACKOFF_DELAY = 1024000 ;
100
+ BACKOFF_INITIAL_DELAY = 1000
101
+ MAX_BACKOFF_DELAY = 1024000
74
102
75
103
def __init__ (self , api_key , url = GCM_URL , proxy = None ):
76
104
""" api_key : google api key
@@ -80,17 +108,17 @@ def __init__(self, api_key, url=GCM_URL, proxy=None):
80
108
self .api_key = api_key
81
109
self .url = url
82
110
if proxy :
83
- if isinstance (proxy ,basestring ):
111
+ if isinstance (proxy , basestring ):
84
112
protocol = url .split (':' )[0 ]
85
- proxy = {protocol :proxy }
113
+ proxy = {protocol : proxy }
86
114
87
115
auth = urllib2 .HTTPBasicAuthHandler ()
88
- opener = urllib2 .build_opener (urllib2 .ProxyHandler (proxy ), auth , urllib2 .HTTPHandler )
116
+ opener = urllib2 .build_opener (
117
+ urllib2 .ProxyHandler (proxy ), auth , urllib2 .HTTPHandler )
89
118
urllib2 .install_opener (opener )
90
119
91
-
92
120
def construct_payload (self , registration_ids , data = None , collapse_key = None ,
93
- delay_while_idle = False , time_to_live = None , is_json = True , dry_run = False ):
121
+ delay_while_idle = False , time_to_live = None , is_json = True , dry_run = False ):
94
122
"""
95
123
Construct the dictionary mapping of parameters.
96
124
Encodes the dictionary into JSON if for json requests.
@@ -101,7 +129,8 @@ def construct_payload(self, registration_ids, data=None, collapse_key=None,
101
129
"""
102
130
103
131
if time_to_live :
104
- if time_to_live > 2419200 or time_to_live < 0 :
132
+ four_weeks_in_secs = 2419200
133
+ if not (0 <= time_to_live <= four_weeks_in_secs ):
105
134
raise GCMInvalidTtlException ("Invalid time to live value" )
106
135
107
136
if is_json :
@@ -119,7 +148,7 @@ def construct_payload(self, registration_ids, data=None, collapse_key=None,
119
148
if delay_while_idle :
120
149
payload ['delay_while_idle' ] = delay_while_idle
121
150
122
- if time_to_live >= 0 :
151
+ if time_to_live :
123
152
payload ['time_to_live' ] = time_to_live
124
153
125
154
if collapse_key :
@@ -146,7 +175,8 @@ def make_request(self, data, is_json=True):
146
175
headers = {
147
176
'Authorization' : 'key=%s' % self .api_key ,
148
177
}
149
- # Default Content-Type is defaulted to application/x-www-form-urlencoded;charset=UTF-8
178
+ # Default Content-Type is defaulted to
179
+ # application/x-www-form-urlencoded;charset=UTF-8
150
180
if is_json :
151
181
headers ['Content-Type' ] = 'application/json'
152
182
@@ -158,16 +188,19 @@ def make_request(self, data, is_json=True):
158
188
response = urllib2 .urlopen (req ).read ()
159
189
except urllib2 .HTTPError as e :
160
190
if e .code == 400 :
161
- raise GCMMalformedJsonException ("The request could not be parsed as JSON" )
191
+ raise GCMMalformedJsonException (
192
+ "The request could not be parsed as JSON" )
162
193
elif e .code == 401 :
163
- raise GCMAuthenticationException ("There was an error authenticating the sender account" )
194
+ raise GCMAuthenticationException (
195
+ "There was an error authenticating the sender account" )
164
196
elif e .code == 503 :
165
197
raise GCMUnavailableException ("GCM service is unavailable" )
166
198
else :
167
199
error = "GCM service error: %d" % e .code
168
200
raise GCMUnavailableException (error )
169
201
except urllib2 .URLError as e :
170
- raise GCMConnectionException ("There was an internal error in the GCM server while trying to process the request" )
202
+ raise GCMConnectionException (
203
+ "There was an internal error in the GCM server while trying to process the request" )
171
204
172
205
if is_json :
173
206
response = json .loads (response )
@@ -179,11 +212,14 @@ def raise_error(self, error):
179
212
elif error == 'Unavailable' :
180
213
# Plain-text requests will never return Unavailable as the error code.
181
214
# http://developer.android.com/guide/google/gcm/gcm.html#error_codes
182
- raise GCMUnavailableException ("Server unavailable. Resent the message" )
215
+ raise GCMUnavailableException (
216
+ "Server unavailable. Resent the message" )
183
217
elif error == 'NotRegistered' :
184
- raise GCMNotRegisteredException ("Registration id is not valid anymore" )
218
+ raise GCMNotRegisteredException (
219
+ "Registration id is not valid anymore" )
185
220
elif error == 'MismatchSenderId' :
186
- raise GCMMismatchSenderIdException ("A Registration ID is tied to a certain group of senders" )
221
+ raise GCMMismatchSenderIdException (
222
+ "A Registration ID is tied to a certain group of senders" )
187
223
elif error == 'MessageTooBig' :
188
224
raise GCMMessageTooBigException ("Message can't exceed 4096 bytes" )
189
225
@@ -202,7 +238,8 @@ def handle_plaintext_response(self, response):
202
238
203
239
def handle_json_response (self , response , registration_ids ):
204
240
errors = group_response (response , registration_ids , 'error' )
205
- canonical = group_response (response , registration_ids , 'registration_id' )
241
+ canonical = group_response (
242
+ response , registration_ids , 'registration_id' )
206
243
207
244
info = {}
208
245
if errors :
@@ -218,7 +255,7 @@ def extract_unsent_reg_ids(self, info):
218
255
return []
219
256
220
257
def plaintext_request (self , registration_id , data = None , collapse_key = None ,
221
- delay_while_idle = False , time_to_live = None , retries = 5 , dry_run = False ):
258
+ delay_while_idle = False , time_to_live = None , retries = 5 , dry_run = False ):
222
259
"""
223
260
Makes a plaintext request to GCM servers
224
261
@@ -251,7 +288,7 @@ def plaintext_request(self, registration_id, data=None, collapse_key=None,
251
288
raise IOError ("Could not make request after %d attempts" % attempt )
252
289
253
290
def json_request (self , registration_ids , data = None , collapse_key = None ,
254
- delay_while_idle = False , time_to_live = None , retries = 5 , dry_run = False ):
291
+ delay_while_idle = False , time_to_live = None , retries = 5 , dry_run = False ):
255
292
"""
256
293
Makes a JSON request to GCM servers
257
294
@@ -265,7 +302,8 @@ def json_request(self, registration_ids, data=None, collapse_key=None,
265
302
if not registration_ids :
266
303
raise GCMMissingRegistrationException ("Missing registration_ids" )
267
304
if len (registration_ids ) > 1000 :
268
- raise GCMTooManyRegIdsException ("Exceded number of registration_ids" )
305
+ raise GCMTooManyRegIdsException (
306
+ "Exceded number of registration_ids" )
269
307
270
308
attempt = 0
271
309
backoff = self .BACKOFF_INITIAL_DELAY
0 commit comments