o
    RDi0J                     @  s  d dl mZ d dlZd dlZd dlmZ d dlmZmZm	Z	 ddl
mZ ddlmZ ddlmZmZmZmZmZ dd	lmZ dd
lmZ ddlmZ erZddlmZ ddlmZmZ eeZ dZ!e!d Z"e!d Z#e!d Z$dZ%dZ&dZ'dZ(de Z)dZ*G dd de	Z+G dd deZ,dS )    )annotationsN)	getLogger)TYPE_CHECKINGAny
NamedTuple   )is_put_statement)quote)FILE_PROTOCOLHTTP_HEADER_CONTENT_ENCODING
FileHeaderResultStatuskilobyte)EncryptionMetadata)SnowflakeStorageClient)requests)SnowflakeConnection)SnowflakeFileMetaStorageCredentialzx-goog-meta-z
sfc-digestmatdescencryptiondatazgcs-file-header-digestzgcs-file-header-content-lengthz#gcs-file-header-encryption-metadatazme-central2
   GCS_ACCESS_TOKENc                   @  s*   e Zd ZU ded< ded< dZded< dS )GcsLocationstrbucket_namepathzhttps://storage.googleapis.comendpointN)__name__
__module____qualname____annotations__r    r"   r"   _/var/www/Datamplify/venv/lib/python3.10/site-packages/snowflake/connector/gcs_storage_client.pyr   (   s   
 r   c                      s   e Zd Z	d6d7 fddZd8ddZd8ddZd9ddZd:ddZd; fd d!Zd;d"d#Z	d<d%d&Z
d=d)d*Ze		+	+	d>d?d2d3Ze		+	+	d>d@d4d5Z  ZS )ASnowflakeGCSRestClientFmetar   credentialsr   
stage_infodict[str, Any]cnxr   commandr   unsafe_file_writeboolreturnNonec                   s   t  j||d|d|d || _|| _|| _| | _|jp!|d| _|j	d| _
d|v r6|d  tkp=d|v o=|d | _d|vrEd	n|d | _d
|v oQ|d
 | _| j
rctdt| j
  d	S td |   d	S )zCreates a client object with given stage credentials.

        Args:
            stage_info: Access credentials and info of a stage.

        Returns:
            The client to communicate with GCS.
        F)r&   chunked_transferr+   presignedUrlr   regionuseRegionalUrlendPointNuseVirtualUrlzlen(GCS_ACCESS_TOKEN): z:No access token received from GS, requesting presigned url)super__init__r'   _commandr%   cursor_cursorpresigned_urlgetcredssecurity_tokenlowerGCS_REGION_ME_CENTRAL_2use_regional_urlr   use_virtual_urlloggerdebuglen_update_presigned_url)selfr%   r&   r'   r)   r*   r+   	__class__r"   r#   r7   /   s8   

zSnowflakeGCSRestClient.__init__responserequests.Responsec                 C  s   | j o|jdkS )Ni  )r>   status_code)rG   rJ   r"   r"   r#   _has_expired_tokenb   s   z)SnowflakeGCSRestClient._has_expired_tokenc                 C  s8   | j  o|jdk}|r| jrtd |  || _|S )Ni  z2Presigned url expiration error two times in a row.)r>   rL   last_err_is_presigned_urlrC   rD   raise_for_status)rG   rJ   presigned_url_expiredr"   r"   r#   _has_expired_presigned_urle   s   

z1SnowflakeGCSRestClient._has_expired_presigned_urlchunk_idintchunkbytesc                   s   j d}jd urjj }|r|dkrd}t|tjijrCt	t
ddjjdddddjjd	d
idtjji d fdd}d||}|  t _j_t
t	d_d S )N gzipFullBlobsymmKey1AES_CBC_256)KeyIdEncryptedKey	Algorithmz1.0)ProtocolEncryptionAlgorithmEncryptionLibraryz
Java 5.3.0)EncryptionModeWrappedContentKeyEncryptionAgentContentEncryptionIVKeyWrappingMetadatar-   :tuple[str, dict[str, dict[str | Any, str | None] | bytes]]c                    s~   j s%jd jdjdjvrd njd jj} j}nj } d }|r6	dd| i  d}| |fS )Nlocation/r2   AuthorizationBearer )headersdata)
r;   generate_file_urlr'   dst_file_namelstriprA   r   rB   r>   update)
upload_urlaccess_token	rest_argsrT   gcs_headersr%   rG   r"   r#   generate_url_and_rest_args   s$   


zHSnowflakeGCSRestClient._upload_chunk.<locals>.generate_url_and_rest_argsPUTnull)r-   rf   )r%   dst_compression_typenamer?   r   GCS_METADATA_SFC_DIGESTsha256_digestencryption_metadatarp   GCS_METADATA_ENCRYPTIONDATAPROPjsondumpskeyivGCS_METADATA_MATDESC_KEYr   _send_request_with_retryrO   gcs_file_header_digestupload_sizegcs_file_header_content_lengthloadsr<   #gcs_file_header_encryption_metadata)rG   rR   rT   content_encodingrv   rJ   r"   rt   r#   _upload_chunkt   sJ   



z$SnowflakeGCSRestClient._upload_chunkc                   s   j  d
 fdd}d||}|  ||j d }|jtd rGt	|jt }|rGt
|d d |d t|jv rC|jt nd d	}|jt _t|j _| _d S )Nr-   ,tuple[str, dict[str, dict[str, str] | bool]]c                    st   i } j s.jd  jdjdjvrd njd jj}j}d| | d< nj }| dd}||fS )Nrg   rh   r2   rj   ri   T)rk   stream)	r;   rm   r'   src_file_namero   rA   r   rB   r>   )ru   download_urlrr   rs   r%   rG   r"   r#   rv      s"   


zISnowflakeGCSRestClient.download_chunk.<locals>.generate_url_and_rest_argsGETrb   r\   rd   r   r   r   )r-   r   )r%   r   rO   write_downloaded_chunkcontentrk   r<   r~   r   r   r   r   r{   r   rE   r   r   )rG   rR   rv   rJ   r}   r   r"   r   r#   download_chunk   s.   




z%SnowflakeGCSRestClient.download_chunkc                   s    t    tj| j| j_d S )N)r6   finish_downloadosr   getsizefull_dst_file_namer%   src_file_size)rG   rH   r"   r#   r      s   
z&SnowflakeGCSRestClient.finish_downloadc                 C  s   t d |  }|sdS | jj}| j}|||}t d| | j|}|	dt
 	dt
 }|	d| j_|	d| _dS )zUpdates the file metas with presigned urls if any.

        Currently only the file metas generated for PUT/GET on a GCP account need the presigned urls.
        zUpdating presigned urlNzgetting presigned url for %srl   	stageInfor1   )rC   rD   %_get_local_file_path_from_put_commandr%   rn   r8   replacer:   _execute_helperr<   dictr;   )rG   file_path_to_be_replacedfile_path_to_replace_withcommand_with_single_fileretr'   r"   r"   r#   rF     s   
z,SnowflakeGCSRestClient._update_presigned_url
str | Nonec           	      C  s   | j }t| j vst|sdS |t}||d  dk}|tt7 }d}|r7|d|}||kr5||| }|S g }dD ]}|||}|dkrL||g7 }q;|rSt|nd}||kra||| }|S |dkrk||d }|S )zGet the local file path from PUT command (Logic adopted from JDBC, written by Polita).

        Args:
            command: Command to be parsed and get the local file path out of.

        Returns:
            The local file path.
        Nr   'rV   ) 
;r/   )r8   r
   r   findrE   min)	rG   r*   file_path_begin_indexis_file_path_quoted	file_pathfile_path_end_index
index_list	delimiterindexr"   r"   r#   r   *  s2   	

z<SnowflakeGCSRestClient._get_local_file_path_from_put_commandfilenameFileHeader | Nonec           
        s,  j }|jtjks|jtjkrt|j|j|jdS j	r"tj
|_dS  fdd}d}dj|< d||}|jdkrBtj
|_dS |jdkr|jtd}t|jd	d
}tddd}|jtdrt|jt }	|	rt|	d d |	d t|jv r|jt ndd}tj|_t|||dS |  dS )aF  Gets the remote file's metadata.

        Args:
            filename: Not applicable to GCS.

        Returns:
            The file header, with expected properties populated or None, based on how the request goes with the
            storage provider.

        Notes:
            Sometimes this method is called to verify that the file has indeed been uploaded. In cases of presigned
            url, we have no way of verifying that, except with the http status code of 200 which we have already
            confirmed and set the meta.result_status = UPLOADED/DOWNLOADED.
        )digestcontent_lengthr}   c                    sZ    jd  djdjvrd njd jj} ddj i}d|i}| |fS )Nrg   rh   r2   ri   rj   rk   )rm   r'   ro   rA   r   rB   r>   )urlru   rs   r   rG   r"   r#   &generate_url_and_authenticated_headerso  s   
zVSnowflakeGCSRestClient.get_file_header.<locals>.generate_url_and_authenticated_headersHEADr   i  N   zcontent-length0rV   rb   r\   rd   r   )r%   result_statusr   UPLOADED
DOWNLOADEDr   r   r   r   r;   NOT_FOUND_FILEretry_countr   rL   rk   r<   r{   rS   r   r~   r   r   r   rO   )
rG   r   r%   r   retry_idrJ   r   r   r}   encryption_datar"   r   r#   get_file_headerR  sV   





	z&SnowflakeGCSRestClient.get_file_headerNstage_locationrA   r2   r   rB   r   c                 C  s   | }d}d| v r'| d|  d }| |  dd d  }|r'|ds'|d7 }|rD|dr4|d d }|ds=d| }t|||dS |rQt||d| ddS |r`t||d	|  d
dS t||dS )NrV   rh   r   r   r/   zhttps://)r   r   r   z.storage.googleapis.comzhttps://storage.z.rep.googleapis.com)r   r   )r   endswith
startswithr   r?   )r   rA   r2   r   rB   container_namer   r"   r"   r#   get_location  s4   


z#SnowflakeGCSRestClient.get_locationc                 C  sT   t | ||||}|j | }|r|j dt| S |j d|j dt| S )Nrh   )r$   r   r   r   r	   r   )r   r   rA   r2   r   rB   gcs_locationfull_file_pathr"   r"   r#   rm     s   	
z(SnowflakeGCSRestClient.generate_file_url)F)r%   r   r&   r   r'   r(   r)   r   r*   r   r+   r,   r-   r.   )rJ   rK   r-   r,   )rR   rS   rT   rU   r-   r.   )rR   rS   r-   r.   )r-   r.   )r-   r   )r   r   r-   r   )FNNF)r   r   rA   r   r2   r   r   r   rB   r,   r-   r   )r   r   r   r   rA   r   r2   r   r   r   rB   r,   r-   r   )r   r   r    r7   rM   rQ   r   r   r   rF   r   r   staticmethodr   rm   __classcell__r"   r"   rH   r#   r$   .   s.    
3


N8

)
(S%r$   )-
__future__r   r   r   loggingr   typingr   r   r   	_sql_utilr   compatr	   	constantsr
   r   r   r   r   encryption_utilr   storage_clientr   vendoredr   
connectionr   file_transfer_agentr   r   r   rC   GCS_METADATA_PREFIXr{   r   r~   GCS_FILE_HEADER_DIGESTGCS_FILE_HEADER_CONTENT_LENGTH#GCS_FILE_HEADER_ENCRYPTION_METADATAr@   CONTENT_CHUNK_SIZEACCESS_TOKENr   r$   r"   r"   r"   r#   <module>   s6   