o
    g/                     @   sN   d Z ddlZddlZddlZddlZddlZddlZddlZG dd dZdS )z}
This file contains a class to manage tokens
Coded by Tyler Bowers
Github: https://github.com/tylerebowers/Schwab-API-Python
    Nc                   @   sp   e Zd ZdddZdedefddZd	ed
edefddZdd Z	dddZ
dd Zdd Zdd Zdd ZdS )Tokenstokens.jsonTc           
   
      s  |du rt d|du rt d|du rt d|du r t dt|dks,t|dkr0t d|d	d
 dkr<t d|d dkrFt d|d dkrPt d| _| _| _| _d _d _d _t	j	j
jt	jjd _t	j	j
jt	jjd _d _d _| _d  vr|r    jjr jt	j	t	jj j   }td|d	k rdnd tt|d ddtt|d d ddtt|d dd  jt	j	t	jj j   }td|d	k rdnd tt|d ddtt|d d ddtt|d dd n jjr tdt| d |r'   |r; fd d!}	tj|	d"d#  dS  jjrFtd$ dS dS )%a  
        Initialize a tokens manager
        :param client: client object (only used for .verbose setting)
        :type client: Client
        :param app_key: app key credentials
        :type app_key: str
        :param app_secret: app secret credentials
        :type app_secret: str
        :param callback_url: url for callback
        :type callback_url: str
        :param tokens_file: path to tokens file
        :type tokens_file: str
        Nz#[Schwabdev] app_key cannot be None.z&[Schwabdev] app_secret cannot be None.z([Schwabdev] callback_url cannot be None.z'[Schwabdev] tokens_file cannot be None.       z1[Schwabdev] App key or app secret invalid length.r      httpsz'[Schwabdev] callback_url must be https./z8[Schwabdev] callback_url cannot be path (ends with "/").z'[Schwabdev] Tokens file cannot be path.)tzinfoi  i:	 z$[Schwabdev] Access token expires in -   02H:<   M:Sz%[Schwabdev] Refresh token expires in zG[Schwabdev] Token file does not exist or invalid formatting, creating ""c                      s   	     td q)NT   )update_tokenstimesleep selfr   //var/www/html/StreammingVPS/schwabdev/tokens.pycheckerP   s   
z Tokens.__init__.<locals>.checkerT)targetdaemonz>[Schwabdev] Warning: Tokens will not be updated automatically.) 	Exceptionlen_client_app_key_app_secret_callback_urlaccess_tokenrefresh_tokenid_tokendatetimeminreplacetimezoneutc_access_token_issued_refresh_token_issued_access_token_timeout_refresh_token_timeout_tokens_file_read_tokensr   verbosenowtotal_secondsprintintabsstrupdate_refresh_token	threadingThreadstart)
r   clientapp_key
app_secretcallback_urltokens_fileupdate_tokens_autoat_deltart_deltar   r   r   r   __init__   s^   
 Z Z

zTokens.__init__
grant_typecodec                 C   st   dt t| j d| j dd dd}|dkr$d|| jd}n|dkr.d|d	}ntd
tj	d||dS )a  
        Makes API calls for auth code and refresh tokens
        :param grant_type: 'authorization_code' or 'refresh_token'
        :type grant_type: str
        :param code: authorization code
        :type code: str
        :return: response
        :rtype: requests.Response
        zBasic :zutf-8z!application/x-www-form-urlencoded)AuthorizationzContent-Typeauthorization_code)rG   rH   redirect_urir&   )rG   r&   zGInvalid grant type; options are 'authorization_code' or 'refresh_token'z(https://api.schwabapi.com/v1/oauth/token)headersdata)
base64	b64encodebytesr"   r#   decoder$   r   requestspost)r   rG   rH   rM   rN   r   r   r   _post_oauth_tokenY   s   (zTokens._post_oauth_token	at_issued	rt_issuedtoken_dictionaryc              
   C   s   | d| _| d| _| d| _|| _|| _z.t| jd}| | |d}t	j
||ddd W d	   W d	S 1 s?w   Y  W d	S  tya } zt| td
 W Y d	}~d	S d	}~ww )a6  
        Writes token file and sets variables
        :param at_issued: access token issued
        :type at_issued: datetime.pyi
        :param rt_issued: refresh token issued
        :type rt_issued: datetime.pyi
        :param token_dictionary: token dictionary
        :type token_dictionary: dict
        r%   r&   r'   w)access_token_issuedrefresh_token_issuedrX   F   )ensure_asciiindentNz'[Schwabdev] Could not write tokens file)getr%   r&   r'   r-   r.   openr1   	isoformatjsondumpr   r6   )r   rV   rW   rX   fto_writeer   r   r   _write_tokensq   s$   
&zTokens._write_tokensc              
   C   s   zQt | jd@}t|}|d}|d| _|d| _|d| _tj	|d| _
tj	|d| _| j
| j|fW  d   W S 1 sJw   Y  W dS  tyh } zt| W Y d}~d	S d}~ww )
z
        Reads token file and sets variables
        :return: access token issued, refresh token issued, token dictionary
        :rtype: datetime.pyi, datetime.pyi, dict
        rrX   r%   r&   r'   rZ   r[   N)NNN)r`   r1   rb   loadr_   r%   r&   r'   r(   fromisoformatr-   r.   r   r6   )r   rd   drX   rf   r   r   r   r2      s    

(	zTokens._read_tokensFc              
   C   s   | j tjtjj| j   }|dk rAtd|dk rdnd tt	|d ddtt	|d d	 dd
tt	|d	 dd |dk sG|rQtd | 
  dS | jtjtjj| j   dk rq| jjrktd |   dS dS )z
        Checks if tokens need to be updated and updates if needed (only access token is automatically updated)
        :param force: force update of refresh token (also updates access token)
        :type force: bool
        i  z1[Schwabdev] The refresh token will expire soon! (r   r   r   r   r   r   r   r   zS remaining)z*[Schwabdev] The refresh token has expired!=   zA[Schwabdev] The access token has expired, updating automatically.N)r0   r(   r4   r+   r,   r.   r5   r6   r7   r8   r:   r/   r-   r!   r3   update_access_token)r   forcerE   r   r   r   r      s    Z$zTokens.update_tokensc                 C   sn   |  d| j}|jr,tjtjj}| || j|	  | j
jr*td| j  dS dS t|j td dS )zD
        "refresh" the access token using the refresh token
        r&   z"[Schwabdev] Access token updated: zS[Schwabdev] Could not get new access token, refresh_token probably expired randomlyN)rU   r&   okr(   r4   r+   r,   rg   r.   rb   r!   r3   r6   r-   text)r   responserV   r   r   r   rm      s    
zTokens.update_access_tokenc                 C   s   d| j  d| j S )z'
        Get authorization url
        z7https://api.schwabapi.com/v1/oauth/authorize?client_id=z&redirect_uri=)r"   r$   r   r   r   r   get_refresh_token_auth_url   s   z!Tokens.get_refresh_token_auth_urlc                 C   s   | dr||dd |d  d}n|}| d|}|jr?tjtjj}| |||	  | j
jr=td d	S d	S t|j td d	S )
z
        Get new access and refresh tokens using callback url or authorization code.
        :param url_or_code: callback url (full url) or authorization code (the code=... in url)
        :type url_or_code: str
        zhttps://zcode=r   z%40@rK   z-[Schwabdev] Refresh and Access tokens updatedz[Schwabdev] Could not get new refresh and access tokens, check these:
1. App status is "Ready For Use".
2. App key and app secret are valid.
3. You pasted the whole url within 30 seconds. (it has a quick expiration)N)
startswithindexrU   ro   r(   r4   r+   r,   rg   rb   r!   r3   r6   rp   )r   url_or_coderH   rq   r4   r   r   r   update_refresh_token_from_code   s   
$
z%Tokens.update_refresh_token_from_codec                 C   s6   |   }td|  t| td}| | dS )zM
        Get new access and refresh tokens using authorization code.
        z"[Schwabdev] Open to authenticate: z?[Schwabdev] After authorizing, paste the address bar url here: N)rr   r6   
webbrowserr`   inputrw   )r   auth_urlresponse_urlr   r   r   r:      s
   
zTokens.update_refresh_tokenN)r   T)F)__name__
__module____qualname__rF   r9   rU   r(   dictrg   r2   r   rm   rr   rw   r:   r   r   r   r   r      s    
I
r   )	__doc__rb   r   rO   rS   r(   r;   rx   r   r   r   r   r   <module>   s    