
    "                         d Z ddlmZ ddlmZ ddlmZ ddlm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  G d
 de      Zy)z-Helper class for streaming resumable uploads.    )absolute_import)print_function)division)unicode_literalsN)CommandException)GetJsonResumableChunkSize)UTF8c                   `    e Zd ZdZd
dZed        ZddZd Zd Z	e
j                  fdZd Zy	)#ResumableStreamingJsonUploadWrappera#  Wraps an input stream in a buffer for resumable uploads.

  This class takes a non-seekable input stream, buffers it, and exposes it
  as a stream with limited seek capabilities such that it can be used in a
  resumable JSON API upload.

  max_buffer_size bytes of buffering is supported.
  c                     || _         |s'|t               k  rt        d|dt               d      || _        t	        j
                         | _        d| _        d| _        d| _	        y)av  Initializes the wrapper.

    Args:
      stream: Input stream.
      max_buffer_size: Maximum size of internal buffer; should be >= the chunk
          size of the resumable upload API to ensure that at least one full
          chunk write can be replayed in the event of a server error.
      test_small_buffer: Skip check for buffer size vs. chunk size, for testing.
    z4Resumable streaming upload created with buffer size z#, JSON resumable upload chunk size z`. Buffer size must be >= JSON resumable upload chunk size to ensure that uploads can be resumed.r   N)
_orig_fpr   r   _max_buffer_sizecollectionsdeque_buffer_buffer_start_buffer_end	_position)selfstreammax_buffer_sizetest_small_buffers       3platform/gsutil/gslib/resumable_streaming_upload.py__init__z,ResumableStreamingJsonUploadWrapper.__init__)   sj     DM3L3N!N
 ./H/JL M M ,D$$&DLDDDN    c                 0    t        | j                  dd      S )z<Returns the mode of the underlying file descriptor, or None.modeN)getattrr   r   s    r   r   z(ResumableStreamingJsonUploadWrapper.modeC   s     4==&$//r   c                 T   |du xs |dk  }|r| j                   }n|}d}g }| j                  | j                  k  r(| j                  }d}|t	        | j
                  |         z   | j                  k  rI|t	        | j
                  |         z  }|dz  }|t	        | j
                  |         z   | j                  k  rI|| j                  k  r|dkD  rt	        | j
                  |         }| j                  |z
  }	||	z
  }
t        |
|      }|j                  | j
                  |   |	|	|z           ||z  }||z  }|dz  }| xj                  |z  c_        || j                  k  r|dkD  r|rd| j                  j                  |      }t	        |      }|s|}n"|j                  |       dj                  |      }| xj                  |z  c_        |S |r|| j                  j                  |      }|s|}n"|j                  |       dj                  |      }t	        |      }|r*| xj                  |z  c_        | j
                  j                  |       | xj                  |z  c_        d}| j                  | j                  z
  | j                   kD  r_| j
                  j                         }| xj                  t	        |      z  c_        | j                  | j                  z
  | j                   kD  r_|r\| j                   | j                  | j                  z
  z
  }|r4| j
                  j                  || d        | xj                  |z  c_        |S t        j                  r6|r4|D cg c])  }t        |t               r|j#                  t$              n|+ }}|rdj                  |      nd}|S c c}w )z"Reads from the wrapped stream.

    Args:
      size: The amount of bytes to read. If omitted or negative, the entire
          contents of the stream will be read and returned.

    Returns:
      Bytes from the wrapped stream.
    Nr   r      )r   r   r   r   lenr   minappendr   readjoinpopleft
appendleftsixPY3
isinstancestrencoder	   )r   sizeread_all_bytesbytes_remainingdatabuffered_datapos_in_bufferbuffer_index
buffer_lenoffset_from_positionbytes_available_this_buffer	read_sizenew_datadata_lenoldest_datarefill_amountbds                    r   r%   z(ResumableStreamingJsonUploadWrapper.readH   s    T\-TAXN--ooDM~~((( ((mlC\ :;;dnnL 	T\\,788 C\ :;;dnnL D,,,11Dl34
#~~=&03G&G#3_E	T\\,723G'4() 	* 	9$#)# D,,,11D"  ##D)hXhX&xx&
nn n@ K? 
##O4hX&xx&Xh	("H%H$!3!33d6K6KK,,.+


K 0
0
 !3!33d6K6KK //43C3C373E3E4F G-LL##K$@A-/ K 
 &%" ",B!4biio"<%   )6SXXm$3dKs   .N%c                     | j                   S )z$Returns the current stream position.)r   r   s    r   tellz(ResumableStreamingJsonUploadWrapper.tell   s    >>r   c                      y)z/Returns true since limited seek support exists.T r   s    r   seekablez,ResumableStreamingJsonUploadWrapper.seekable   s    r   c           	         |t         j                  k(  rO|| j                  k  s|| j                  kD  r)t	        d|d| j                  d| j                  d      || _        y|t         j                  k(  ry|| j                  kD  rt	        d|d| j                  d      | j                  | j                        r	 | j                  | j                        r| xj
                  |z  c_        yt	        d|d	|d
      )zSeeks on the buffered stream.

    Args:
      offset: The offset to seek to; must be within the buffer bounds.
      whence: Must be os.SEEK_SET.

    Raises:
      CommandException if an unsupported seek mode or position is used.
    z]Unable to resume upload because of limited buffering available for streaming uploads. Offset z# was requested, but only data from z to z is buffered.zInvalid SEEK_END offset z on streaming upload. Only z can be buffered.z-Invalid seek mode on streaming upload. (mode z	, offset )N)	osSEEK_SETr   r   r   r   SEEK_ENDr   r%   )r   offsetwhences      r   seekz(ResumableStreamingJsonUploadWrapper.seek   s     	$$$	$1A1A(A !'(:(:D<L<L	 N O 	O dn	2;;		$''	' &(=(= ? @ 	@ IId++, IId++, nnn7=vG H Hr   c                 6    | j                   j                         S )N)r   closer   s    r   rL   z)ResumableStreamingJsonUploadWrapper.close   s    ==  r   N)F))__name__
__module____qualname____doc__r   propertyr   r%   r?   rB   rE   rF   rJ   rL   rA   r   r   r   r      sF    4 0 0cJ !# HB!r   r   )rQ   
__future__r   r   r   r   r   rE   r)   gslib.exceptionr   gslib.utils.boto_utilr   gslib.utils.constantsr	   objectr   rA   r   r   <module>rX      s6    4 & %  '  	 
 , ; &x!& x!r   