
    -                        S r SSKrSSKrSSKrSSKrSSKrSSKrSSKJr  SSK	J
r
  SSK	Jr  Sr\R                  " \5      r0 r\R"                  " 5       rS rS rS	 r " S
 S\5      rS r " S S\R2                  5      rg)a	  Multiprocess file credential storage.

This module provides file-based storage that supports multiple credentials and
cross-thread and process access.

This module supersedes the functionality previously found in `multistore_file`.

This module provides :class:`MultiprocessFileStorage` which:
    * Is tied to a single credential via a user-specified key. This key can be
      used to distinguish between multiple users, client ids, and/or scopes.
    * Can be safely accessed and refreshed across threads and processes.

Process & thread safety guarantees the following behavior:
    * If one thread or process refreshes a credential, subsequent refreshes
      from other processes will re-fetch the credentials from the file instead
      of performing an http request.
    * If two processes or threads attempt to refresh concurrently, only one
      will be able to acquire the lock and refresh, with the deadlock caveat
      below.
    * The interprocess lock will not deadlock, instead, the if a process can
      not acquire the interprocess lock within ``INTERPROCESS_LOCK_DEADLINE``
      it will allow refreshing the credential but will not write the updated
      credential to disk, This logic happens during every lock cycle - if the
      credentials are refreshed again it will retry locking and writing as
      normal.

Usage
=====

Before using the storage, you need to decide how you want to key the
credentials. A few common strategies include:

    * If you're storing credentials for multiple users in a single file, use
      a unique identifier for each user as the key.
    * If you're storing credentials for multiple client IDs in a single file,
      use the client ID as the key.
    * If you're storing multiple credentials for one user, use the scopes as
      the key.
    * If you have a complicated setup, use a compound key. For example, you
      can use a combination of the client ID and scopes as the key.

Create an instance of :class:`MultiprocessFileStorage` for each credential you
want to store, for example::

    filename = 'credentials'
    key = '{}-{}'.format(client_id, user_id)
    storage = MultiprocessFileStorage(filename, key)

To store the credentials::

    storage.put(credentials)

If you're going to continue to use the credentials after storing them, be sure
to call :func:`set_store`::

    credentials.set_store(storage)

To retrieve the credentials::

    storage.get(credentials)

    N)	iteritems)_helpers)client   c                     [         R                  R                  U 5      (       a  g[        U S5      R	                  5         [
        R                  SR                  U 5      5        g)zuCreates the an empty file if it does not already exist.

Returns:
    True if the file was created, False otherwise.
Fza+bzCredential file {0} createdT)ospathexistsopencloseloggerinfoformatfilenames    Alib/third_party/oauth2client/contrib/multiprocess_file_storage.py_create_file_if_neededr   d   sJ     
ww~~h 	Xu##%188BC    c                     U R                  S5        [        R                  " U 5      nUR                  S5      S:w  a  [        R                  S5        0 $ 0 n[        UR                  S0 5      5       H?  u  p4 [        R                  " U5      n[        R                  R                  U5      nXbU'   MA     U$ ! [         a    [        R                  S5        0 s $ f = f!   [        R                  SR                  U5      5         M  = f)a  Load credentials from the given file handle.

The file is expected to be in this format:

    {
        "file_version": 2,
        "credentials": {
            "key": "base64 encoded json representation of credentials."
        }
    }

This function will warn and return empty credentials instead of raising
exceptions.

Args:
    credentials_file: An open file handle.

Returns:
    A dictionary mapping user-defined keys to an instance of
    :class:`oauth2client.client.Credentials`.
r   z@Credentials file could not be loaded, will ignore and overwrite.file_version   z=Credentials file is not version 2, will ignore and overwrite.credentialsz)Invalid credential {0} in file, ignoring.)seekjsonload	Exceptionr   warninggetr   base64	b64decoder   Credentialsnew_from_jsonr   )credentials_filedatar   keyencoded_credentialcredential_json
credentials          r   _load_credentials_filer)   s   s    ,a yy)* xx1$	 	K#,TXXmR-H#I	I$../ABO++99/JJ)	 $J /  	 		&	INN;BB3GIs   'B7 89C7!CC&Dc                 N   S0 S.n[        U5       HZ  u  p4UR                  5       n[        R                  " [        R
                  " [        R                  " U5      5      5      nXbS   U'   M\     U R                  S5        [        R                  " X 5        U R                  5         g)a  Writes credentials to a file.

Refer to :func:`_load_credentials_file` for the format.

Args:
    credentials_file: An open file handle, must be read/write.
    credentials: A dictionary mapping user-defined keys to an instance of
        :class:`oauth2client.client.Credentials`.
r   )r   r   r   r   N)r   to_jsonr   _from_bytesr   	b64encode	_to_bytesr   r   dumptruncate)r#   r   r$   r%   r(   r'   r&   s          r   _write_credentials_filer1      s     b1D$[1$,,.%11&2B2B/31 2#5]C 	 2 !IId%r   c                   N    \ rS rSrSrS rS rS rS rS r	S r
S	 rS
 rS rSrg)_MultiprocessStorageBackend   a  Thread-local backend for multiprocess storage.

Each process has only one instance of this backend per file. All threads
share a single instance of this backend. This ensures that all threads
use the same thread lock and process lock when accessing the file.
c                     S U l         Xl        [        R                  " SR	                  U5      5      U l        [        R                  " 5       U l        SU l	        0 U l
        g )Nz{0}.lockF)_file	_filename	fastenersInterProcessLockr   _process_lock	threadingLock_thread_lock
_read_only_credentials)selfr   s     r   __init__$_MultiprocessStorageBackend.__init__   sM    
!&77h')%NN,r   c                     U R                   (       d  g[        U R                   5      nU R                  R                  U5        [        R                  S5        g)z)(Re-)loads the credentials from the file.NzRead credential file)r6   r)   r?   updater   debug)r@   loaded_credentialss     r   _load_credentials-_MultiprocessStorageBackend._load_credentials   s=    zz3DJJ?  !34+,r   c                     U R                   (       a  [        R                  S5        g [        U R                  U R
                  5        [        R                  SR                  U R                  5      5        g )Nz+In read-only mode, not writing credentials.zWrote credential file {0}.)r>   r   rE   r1   r6   r?   r   r7   r@   s    r   _write_credentials._MultiprocessStorageBackend._write_credentials   sI    ??LLFG

D,=,=>188HIr   c                    U R                   R                  5         U R                  R                  [        S9nU(       a8  [	        U R
                  5        [        U R
                  S5      U l        SU l        Om[        R                  S5        [        R                  R                  U R
                  5      (       a  [        U R
                  S5      U l        OS U l        SU l        U R                  5         g )N)timeoutzr+FzFailed to obtain interprocess lock for credentials. If a credential is being refreshed, other processes may not see the updated access token and refresh as well.rT)r=   acquirer:   INTERPROCESS_LOCK_DEADLINEr   r7   r   r6   r>   r   warnr   r	   r
   rG   )r@   lockeds     r   acquire_lock(_MultiprocessStorageBackend.acquire_lock   s    !!###++4N+O"4>>2dnnd3DJ#DO KKHI ww~~dnn--!$..#6
!
"DO r   c                     U R                   b!  U R                   R                  5         S U l         U R                  (       d  U R                  R	                  5         U R
                  R	                  5         g N)r6   r   r>   r:   releaser=   rJ   s    r   release_lock(_MultiprocessStorageBackend.release_lock   sN    ::!JJDJ&&(!!#r   c                 T    Uc  gUR                   (       a  gUR                  (       a  gg)NTF)invalidaccess_token_expiredr@   r   s     r   _refresh_predicate._MultiprocessStorageBackend._refresh_predicate   s&      --r   c                     U R                   R                  US 5      nU R                  U5      (       a,  U R                  5         U R                   R                  US 5      nU$ rW   )r?   r   r_   rG   r@   r%   r   s      r   
locked_get&_MultiprocessStorageBackend.locked_get
  sW    ''++C6 "";//""$++//T:Kr   c                 `    U R                  5         X R                  U'   U R                  5         g rW   )rG   r?   rK   rb   s      r   
locked_put&_MultiprocessStorageBackend.locked_put  s(     !,#!r   c                 |    U R                  5         U R                  R                  US 5        U R                  5         g rW   )rG   r?   poprK   )r@   r%   s     r   locked_delete)_MultiprocessStorageBackend.locked_delete  s0     c4(!r   )r?   r6   r7   r:   r>   r=   N)__name__
__module____qualname____firstlineno____doc__rA   rG   rK   rT   rY   r_   rc   rf   rj   __static_attributes__ r   r   r3   r3      s5    -J!,$"
"r   r3   c                     [         R                  R                  U 5      n [           U [        ;  a  [        U 5      [        U '   [        U    sSSS5        $ ! , (       d  f       g= f)aC  A helper method to get or create a backend with thread locking.

This ensures that only one backend is used per-file per-process, so that
thread and process locks are appropriately shared.

Args:
    filename: The full path to the credential storage file.

Returns:
    An instance of :class:`_MultiprocessStorageBackend`.
N)r   r	   abspath_backends_lock	_backendsr3   r   s    r   _get_backendrw   $  sB     wwx(H	9$"=h"GIh" 
s   %A
A#c                   <    \ rS rSrSrS rS rS rS rS r	S r
S	rg
)MultiprocessFileStoragei8  a+  Multiprocess file credential storage.

Args:
  filename: The path to the file where credentials will be stored.
  key: An arbitrary string used to uniquely identify this set of
      credentials. For example, you may use the user's ID as the key or
      a combination of the client ID and user ID.
c                 0    X l         [        U5      U l        g rW   )_keyrw   _backend)r@   r   r%   s      r   rA    MultiprocessFileStorage.__init__A  s    	$X.r   c                 8    U R                   R                  5         g rW   )r|   rT   rJ   s    r   rT   $MultiprocessFileStorage.acquire_lockE      ""$r   c                 8    U R                   R                  5         g rW   )r|   rY   rJ   s    r   rY   $MultiprocessFileStorage.release_lockH  r   r   c                 x    U R                   R                  U R                  5      nUb  UR                  U 5        U$ )zRetrieves the current credentials from the store.

Returns:
    An instance of :class:`oauth2client.client.Credentials` or `None`.
)r|   rc   r{   	set_store)r@   r(   s     r   rc   "MultiprocessFileStorage.locked_getK  s6     ]]--dii8
!  &r   c                 N    U R                   R                  U R                  U5      $ )zWrites the given credentials to the store.

Args:
    credentials: an instance of
        :class:`oauth2client.client.Credentials`.
)r|   rf   r{   r^   s     r   rf   "MultiprocessFileStorage.locked_putX  s     }}''		;??r   c                 L    U R                   R                  U R                  5      $ )z/Deletes the current credentials from the store.)r|   rj   r{   rJ   s    r   rj   %MultiprocessFileStorage.locked_deletea  s    }}**49955r   )r|   r{   N)rl   rm   rn   ro   rp   rA   rT   rY   rc   rf   rj   rq   rr   r   r   ry   ry   8  s&    /%%@6r   ry   )rp   r   r   loggingr   r;   r8   sixr   oauth2clientr   r   rQ   	getLoggerrl   r   rv   r<   ru   r   r)   r1   objectr3   rw   Storagery   rr   r   r   <module>r      s   =~    	    ! 
  			8	$	!0f .d"& d"N#(+6fnn +6r   