<s> from datetime import datetime , timedelta <EOL> import logging <EOL> import re <EOL> import urllib , urllib2 <EOL> try : <EOL> import json <EOL> except ImportError : <EOL> import simplejson as json <EOL> from google . appengine . api import taskqueue <EOL> from django . core . cache import cache <EOL> from django . utils import importlib <EOL> LOCALHOST = False <EOL> GCM_CONFIG = { '<STR_LIT>' : '<STR_LIT>' , <EOL> } <EOL> try : <EOL> from settings import LOCALHOST , GCM_CONFIG <EOL> except : <EOL> logging . info ( '<STR_LIT>' ) <EOL> pass <EOL> GOOGLE_LOGIN_URL = '<STR_LIT>' <EOL> GOOGLE_GCM_SEND_URL = '<STR_LIT>' if LOCALHOST else '<STR_LIT>' <EOL> GOOGLE_GCM_SEND_URL = '<STR_LIT>' if LOCALHOST else '<STR_LIT>' <EOL> GCM_QUEUE_NAME = '<STR_LIT>' <EOL> GCM_QUEUE_CALLBACK_URL = '<STR_LIT>' <EOL> MEMCACHE_PREFIX = '<STR_LIT>' <EOL> RETRY_AFTER = '<STR_LIT>' <EOL> TOTAL_ERRORS = '<STR_LIT>' <EOL> TOTAL_MESSAGES = '<STR_LIT>' <EOL> class GCMMessage : <EOL> device_tokens = None <EOL> notification = None <EOL> collapse_key = None <EOL> delay_while_idle = None <EOL> time_to_live = None <EOL> def __init__ ( self , device_tokens , notification , collapse_key = None , delay_while_idle = None , time_to_live = None ) : <EOL> if isinstance ( device_tokens , list ) : <EOL> self . device_tokens = device_tokens <EOL> else : <EOL> self . device_tokens = [ device_tokens ] <EOL> self . notification = notification <EOL> self . collapse_key = collapse_key <EOL> self . delay_while_idle = delay_while_idle <EOL> self . time_to_live = time_to_live <EOL> def __unicode__ ( self ) : <EOL> return "<STR_LIT>" % ( repr ( self . device_tokens ) , repr ( self . notification ) , repr ( self . collapse_key ) , repr ( self . delay_while_idle ) , repr ( self . time_to_live ) ) <EOL> def json_string ( self ) : <EOL> if not self . device_tokens or not isinstance ( self . device_tokens , list ) : <EOL> logging . error ( '<STR_LIT>' + repr ( self ) ) <EOL> raise Exception ( '<STR_LIT>' ) <EOL> json_dict = { } <EOL> json_dict [ '<STR_LIT>' ] = self . device_tokens <EOL> if isinstance ( self . notification , dict ) : <EOL> json_dict [ '<STR_LIT:data>' ] = self . notification <EOL> else : <EOL> json_dict [ '<STR_LIT:data>' ] = { '<STR_LIT:data>' : self . notification } <EOL> if self . collapse_key : <EOL> json_dict [ '<STR_LIT>' ] = self . collapse_key <EOL> if self . delay_while_idle : <EOL> json_dict [ '<STR_LIT>' ] = self . delay_while_idle <EOL> if self . time_to_live : <EOL> json_dict [ '<STR_LIT>' ] = self . time_to_live <EOL> json_str = json . dumps ( json_dict ) <EOL> return json_str <EOL> class GCMConnection : <EOL> def notify_device ( self , message , deferred = False ) : <EOL> self . _incr_memcached ( TOTAL_MESSAGES , <NUM_LIT:1> ) <EOL> self . _submit_message ( message , deferred = deferred ) <EOL> def debug ( self , option ) : <EOL> if option == "<STR_LIT>" : <EOL> return "<STR_LIT>" <EOL> elif option == "<STR_LIT>" : <EOL> output = '<STR_LIT>' <EOL> output += "<STR_LIT>" + str ( self . _get_memcached ( TOTAL_MESSAGES ) ) + "<STR_LIT:\n>" <EOL> output += "<STR_LIT>" + str ( self . _get_memcached ( RETRY_AFTER ) ) + "<STR_LIT:\n>" <EOL> output += "<STR_LIT>" + str ( self . _get_memcached ( TOTAL_ERRORS ) ) + "<STR_LIT:\n>" <EOL> return output <EOL> else : <EOL> return "<STR_LIT>" <EOL> def delete_bad_token ( self , bad_device_token ) : <EOL> logging . info ( '<STR_LIT>' + repr ( bad_device_token ) ) <EOL> if '<STR_LIT>' in GCM_CONFIG : <EOL> bad_token_callback_func_path = GCM_CONFIG [ '<STR_LIT>' ] <EOL> mod_path , func_name = bad_token_callback_func_path . rsplit ( '<STR_LIT:.>' , <NUM_LIT:1> ) <EOL> mod = importlib . import_module ( mod_path ) <EOL> logging . info ( '<STR_LIT>' + repr ( ( mod_path , func_name , mod ) ) ) <EOL> bad_token_callback_func = getattr ( mod , func_name ) <EOL> bad_token_callback_func ( bad_device_token ) <EOL> def update_token ( self , old_device_token , new_device_token ) : <EOL> logging . info ( '<STR_LIT>' + repr ( ( old_device_token , new_device_token ) ) ) <EOL> if '<STR_LIT>' in GCM_CONFIG : <EOL> bad_token_callback_func_path = GCM_CONFIG [ '<STR_LIT>' ] <EOL> mod_path , func_name = bad_token_callback_func_path . rsplit ( '<STR_LIT:.>' , <NUM_LIT:1> ) <EOL> mod = importlib . import_module ( mod_path ) <EOL> logging . info ( '<STR_LIT>' + repr ( ( mod_path , func_name , mod ) ) ) <EOL> bad_token_callback_func = getattr ( mod , func_name ) <EOL> bad_token_callback_func ( old_device_token , new_device_token ) <EOL> def login_complete ( self ) : <EOL> pass <EOL> def _gcm_connection_memcache_key ( self , variable_name ) : <EOL> return '<STR_LIT>' + variable_name <EOL> def _get_memcached ( self , variable_name ) : <EOL> memcache_key = self . _gcm_connection_memcache_key ( variable_name ) <EOL> return cache . get ( memcache_key ) <EOL> def _set_memcached ( self , variable_name , value , timeout = None ) : <EOL> memcache_key = self . _gcm_connection_memcache_key ( variable_name ) <EOL> return cache . set ( memcache_key , value , timeout = timeout ) <EOL> def _incr_memcached ( self , variable_name , increment ) : <EOL> memcache_key = self . _gcm_connection_memcache_key ( variable_name ) <EOL> try : <EOL> return cache . incr ( memcache_key , increment ) <EOL> except ValueError : <EOL> return cache . set ( memcache_key , increment ) <EOL> def _requeue_message ( self , message ) : <EOL> taskqueue . add ( queue_name = GCM_QUEUE_NAME , url = GCM_QUEUE_CALLBACK_URL , params = { '<STR_LIT>' : message . device_tokens , '<STR_LIT>' : message . collapse_key , '<STR_LIT>' : message . notification } ) <EOL> def _submit_message ( self , message , deferred = False ) : <EOL> if deferred : <EOL> self . _requeue_message ( message ) <EOL> else : <EOL> self . _send_request ( message ) <EOL> def _send_request ( self , message ) : <EOL> if message . device_tokens == None or message . notification == None : <EOL> logging . error ( '<STR_LIT>' ) <EOL> return False <EOL> retry_after = self . _get_memcached ( RETRY_AFTER ) <EOL> if retry_after != None and retry_after > datetime . now ( ) : <EOL> logging . warning ( '<STR_LIT>' + repr ( retry_after ) + '<STR_LIT>' + repr ( message ) ) <EOL> self . _requeue_message ( message ) <EOL> return <EOL> headers = { <EOL> '<STR_LIT>' : '<STR_LIT>' + GCM_CONFIG [ '<STR_LIT>' ] , <EOL> '<STR_LIT:Content-Type>' : '<STR_LIT:application/json>' <EOL> } <EOL> gcm_post_json_str = '<STR_LIT>' <EOL> try : <EOL> gcm_post_json_str = message . json_string ( ) <EOL> except : <EOL> logging . exception ( '<STR_LIT>' + repr ( message ) ) <EOL> return <EOL> logging . info ( '<STR_LIT>' + repr ( gcm_post_json_str ) ) <EOL> request = urllib2 . Request ( GOOGLE_GCM_SEND_URL , gcm_post_json_str , headers ) <EOL> try : <EOL> resp = urllib2 . urlopen ( request ) <EOL> resp_json_str = resp . read ( ) <EOL> resp_json = json . loads ( resp_json_str ) <EOL> logging . info ( '<STR_LIT>' + repr ( resp_json ) ) <EOL> failure = resp_json [ '<STR_LIT>' ] <EOL> canonical_ids = resp_json [ '<STR_LIT>' ] <EOL> results = resp_json [ '<STR_LIT>' ] <EOL> if failure == <NUM_LIT:0> and canonical_ids == <NUM_LIT:0> : <EOL> return <EOL> else : <EOL> result_index = <NUM_LIT:0> <EOL> for result in results : <EOL> if '<STR_LIT>' in result and '<STR_LIT>' in result : <EOL> try : <EOL> old_device_token = message . device_tokens [ result_index ] <EOL> new_device_token = result [ '<STR_LIT>' ] <EOL> self . update_token ( old_device_token , new_device_token ) <EOL> except : <EOL> logging . exception ( '<STR_LIT>' ) <EOL> elif '<STR_LIT:error>' in result : <EOL> error_msg = result . get ( '<STR_LIT:error>' ) <EOL> try : <EOL> device_token = message . device_tokens [ result_index ] <EOL> self . _on_error ( device_token , error_msg , message ) <EOL> except : <EOL> logging . exception ( '<STR_LIT>' + repr ( error_msg ) ) <EOL> result_index += <NUM_LIT:1> <EOL> except urllib2 . HTTPError , e : <EOL> self . _incr_memcached ( TOTAL_ERRORS , <NUM_LIT:1> ) <EOL> if e . code == <NUM_LIT> : <EOL> logging . error ( '<STR_LIT>' + repr ( gcm_post_json_str ) ) <EOL> elif e . code == <NUM_LIT> : <EOL> logging . error ( '<STR_LIT>' ) <EOL> self . _requeue_message ( message ) <EOL> elif e . code == <NUM_LIT> : <EOL> logging . error ( '<STR_LIT>' + repr ( gcm_post_json_str ) ) <EOL> elif e . code == <NUM_LIT> : <EOL> retry_seconds = int ( resp . headers . get ( '<STR_LIT>' ) ) or <NUM_LIT:10> <EOL> logging . error ( '<STR_LIT>' + str ( retry_seconds ) ) <EOL> retry_timestamp = datetime . now ( ) + timedelta ( seconds = retry_seconds ) <EOL> self . _set_memcached ( RETRY_AFTER , retry_timestamp ) <EOL> self . _requeue_message ( message ) <EOL> else : <EOL> logging . exception ( '<STR_LIT>' + str ( e . code ) + "<STR_LIT:U+0020>" + e . msg + "<STR_LIT:U+0020>" + e . read ( ) ) <EOL> def _on_error ( self , device_token , error_msg , message ) : <EOL> self . _incr_memcached ( TOTAL_ERRORS , <NUM_LIT:1> ) <EOL> if error_msg == "<STR_LIT>" : <EOL> logging . error ( '<STR_LIT>' ) <EOL> elif error_msg == "<STR_LIT>" : <EOL> self . delete_bad_token ( device_token ) <EOL> elif error_msg == "<STR_LIT>" : <EOL> logging . error ( '<STR_LIT>' + repr ( device_token ) ) <EOL> self . delete_bad_token ( device_token ) <EOL> elif error_msg == "<STR_LIT>" : <EOL> self . delete_bad_token ( device_token ) <EOL> elif error_msg == "<STR_LIT>" : <EOL> logging . error ( "<STR_LIT>" ) <EOL> elif error_msg == "<STR_LIT>" : <EOL> logging . error ( "<STR_LIT>" ) <EOL> elif error_msg == "<STR_LIT>" : <EOL> logging . error ( "<STR_LIT>" ) <EOL> elif error_msg == "<STR_LIT>" : <EOL> retry_seconds = <NUM_LIT:10> <EOL> logging . error ( '<STR_LIT>' + str ( retry_seconds ) ) <EOL> retry_timestamp = datetime . now ( ) + timedelta ( seconds = retry_seconds ) <EOL> self . _set_memcached ( RETRY_AFTER , retry_timestamp ) <EOL> self . _requeue_message ( message ) <EOL> elif error_msg == "<STR_LIT>" : <EOL> logging . error ( "<STR_LIT>" + repr ( message ) ) <EOL> else : <EOL> logging . error ( "<STR_LIT>" % ( repr ( error_msg ) , repr ( device_token ) ) ) </s>
