U
    k7gR)                     @   s   d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZ d dl	m
Z
 d dlZd dlmZmZmZmZmZmZ G dd deZdS )    N)HTTPAdapter)Retry)service_account)AuthenticationErrorInvalidDataErrorFCMErrorFCMSenderIdMismatchErrorFCMServerErrorFCMNotRegisteredErrorc                   @   sj   e Zd ZdZdeedddZedd Zddd	Zd
d Z	dd Z
dd Zdd Zdd ZdddZdS )BaseAPIz&https://fcm.googleapis.com/v1/projectsN)service_account_file
project_idc           	      C   s   || _ || _| jd| j d | _d| _|| _t | _|| _|sN|sNt	d|rt
|trd|ksld|kr|| _| jj| |dkrzdd	lm} |  W n tk
r   Y nX || _dS )
a  
        Override existing init function to give ability to use v1 endpoints of Firebase Cloud Messaging API
        Attributes:
            service_account_file (str): path to service account JSON file
            project_id (str): project ID of Google account
            credentials (Credentials): Google oauth2 credentials instance, such as ADC
            proxy_dict (dict): proxy settings dictionary, use proxy (keys: `http`, `https`)
            env (dict): environment settings dictionary, for example "app_engine"
            json_encoder (BaseJSONEncoder): JSON encoder
            adapter (BaseAdapter): adapter instance
        /z/messages:sendNzLPlease provide a service account file path or credentials in the constructorhttphttpsZ
app_enginer   )	appengine)r   r   FCM_END_POINTZFCM_REQ_PROXIEScustom_adapter	threadinglocalthread_localcredentialsr   
isinstancedictrequests_sessionproxiesupdateZrequests_toolbelt.adaptersr   ZmonkeypatchModuleNotFoundErrorjson_encoder)	selfr   r   r   Z
proxy_dictenvr   adapterr    r"   1/tmp/pip-unpacked-wheel-vxwmpmkg/pyfcm/baseapi.py__init__   s8    
zBaseAPI.__init__c                 C   s   t | jdd d krttdddgtjtdgB d}| jp>t|d}t | j_	| jj	
d| | jj	
d	| d
| j_t }| jj|k r| jj	j|   |d | j_| jj	S )Nr      i  i  POST)backoff_factorstatus_forcelistZallowed_methods)max_retrieszhttp://zhttps://r   i  )getattrr   r   ZDEFAULT_ALLOWED_METHODS	frozensetr   r   requestsSessionr   mountZtoken_expirytimeheadersr   request_headers)r   retriesr!   Zcurrent_timestampr"   r"   r#   r   R   s     zBaseAPI.requests_sessionc                 C   sX   | j j| j||d}d|jkrTt|jd dkrTt|jd }t| | ||S |S )N)datatimeoutzRetry-Afterr   )r   postr   r0   intr/   sleepsend_request)r   payloadr4   responseZ
sleep_timer"   r"   r#   r8   f   s      
zBaseAPI.send_requestc                    sJ   dd l }ddlm}  fdd|D }| | j  ||d}|S )Nr   r%   )fetch_tasksc                    s   g | ]} j f |qS r"   )parse_payload).0paramsr   r"   r#   
<listcomp>x   s     z.BaseAPI.send_async_request.<locals>.<listcomp>)Z	end_pointr0   payloadsr4   )asyncioZ	async_fcmr;   Znew_event_loopZrun_until_completer   r1   )r   Zparams_listr4   rB   r;   rA   	responsesr"   r?   r#   send_async_requests   s    	zBaseAPI.send_async_requestc              
   C   sr   zB| j rtjj| j dgd}n| j}tjjj	 }|
| |jW S  tk
rl } zt|W 5 d}~X Y nX dS )z
        Generates access token from credentials.
        If token expires then new access token is generated.
        Returns:
             str: Access token
        z2https://www.googleapis.com/auth/firebase.messaging)ZscopesN)r   r   ZCredentialsZfrom_service_account_filer   googleauth	transportr,   RequestZrefreshtoken	Exceptionr   )r   r   requester"   r"   r#   _get_access_token   s    
zBaseAPI._get_access_tokenc                 C   s   dd|    dS )z
        Generates request headers including Content-Type and Authorization of Bearer token

        Returns:
            dict: request headers
        zapplication/jsonzBearer )zContent-TypeAuthorization)rM   r?   r"   r"   r#   r1      s    
zBaseAPI.request_headersc                 C   s   t j|dd| jdddS )z
        Standardized json.dumps function with separators and sorted keys set

        Args:
            data (dict or list): data to be dumped

        Returns:
            string: json
        ),:TF)
separators	sort_keysclsensure_asciiutf8)jsondumpsr   encode)r   r3   r"   r"   r#   
json_dumps   s    
zBaseAPI.json_dumpsc                 C   s   |j dkr:d|jkr0t|jd dkr0tdq| S nd|j dkrNtdnP|j dkrdt|jn:|j dkrxtd	n&|j d
krt	dntd|j  ddS )a  
        Parses the json response sent back by the server and tries to get out the important return variables

        Returns:
            dict: name (str) - The identifier of the message sent, in the format of projects/*/messages/{message_id}

        Raises:
            FCMServerError: FCM is temporary not available
            AuthenticationError: error authenticating the sender account
            InvalidDataError: data passed to FCM was incorrecly structured
            FCMSenderIdMismatchError: the authenticated sender is different from the sender registered to the token
            FCMNotRegisteredError: device token is missing, not registered, or invalid
           zcontent-lengthr   z2FCM server connection error, the response is emptyi  z4There was an error authenticating the sender accounti  i  zWThe authenticated sender ID is different from the sender ID for the registration token.i  zToken not registeredz)FCM server error: Unexpected status code z.. The server might be temporarily unavailable.N)
status_coder0   r6   r	   rV   r   r   textr   r
   )r   r:   r"   r"   r#   parse_response   s0    






zBaseAPI.parse_responseFc                 C   s,  t  }|r||d< |r||d< |r*||d< |rJt|t rB||d< ntd|rjt|t rb||d< ntd|
rt|
t r|
|d< ntd	|	rt|	t r|	|d
< ntd|rt|t r||d< ntdi |d< |r||d d< |r||d d< |r||d d< |r|s|s|d= | ||dS )z

        :rtype: json
        rI   Ztopic	conditionr3   z,Provided data_payload is in the wrong formatZandroidz.Provided android_config is in the wrong formatZwebpushz.Provided webpush_config is in the wrong formatZapnsz+Provided apns_config is in the wrong formatfcm_optionsz+Provided fcm_options is in the wrong formatZnotificationtitlebodyimage)messageZvalidate_only)r   r   r   rY   )r   Z	fcm_tokenZnotification_titleZnotification_bodyZnotification_imageZdata_payloadZ
topic_nameZtopic_conditionZandroid_configZapns_configZwebpush_configr_   dry_runZfcm_payloadr"   r"   r#   r<      sL    









zBaseAPI.parse_payload)NNNNN)NN)NNNNNNNNNNNF)__name__
__module____qualname__r   strr$   propertyr   r8   rD   rM   r1   rY   r]   r<   r"   r"   r"   r#   r      s>        4

-            r   )rV   osr/   r   r,   Zrequests.adaptersr   urllib3r   Zgoogle.oauth2r   Zgoogle.auth.transport.requestsrE   Zpyfcm.errorsr   r   r   r   r	   r
   objectr   r"   r"   r"   r#   <module>   s    