github.com/aavshr/aws-sdk-go@v1.41.3/aws/types.go (about)

     1  package aws
     2  
     3  import (
     4  	"io"
     5  	"strings"
     6  	"sync"
     7  
     8  	"github.com/aavshr/aws-sdk-go/internal/sdkio"
     9  )
    10  
    11  // ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser. Allows the
    12  // SDK to accept an io.Reader that is not also an io.Seeker for unsigned
    13  // streaming payload API operations.
    14  //
    15  // A ReadSeekCloser wrapping an nonseekable io.Reader used in an API
    16  // operation's input will prevent that operation being retried in the case of
    17  // network errors, and cause operation requests to fail if the operation
    18  // requires payload signing.
    19  //
    20  // Note: If using With S3 PutObject to stream an object upload The SDK's S3
    21  // Upload manager (s3manager.Uploader) provides support for streaming with the
    22  // ability to retry network errors.
    23  func ReadSeekCloser(r io.Reader) ReaderSeekerCloser {
    24  	return ReaderSeekerCloser{r}
    25  }
    26  
    27  // ReaderSeekerCloser represents a reader that can also delegate io.Seeker and
    28  // io.Closer interfaces to the underlying object if they are available.
    29  type ReaderSeekerCloser struct {
    30  	r io.Reader
    31  }
    32  
    33  // IsReaderSeekable returns if the underlying reader type can be seeked. A
    34  // io.Reader might not actually be seekable if it is the ReaderSeekerCloser
    35  // type.
    36  func IsReaderSeekable(r io.Reader) bool {
    37  	switch v := r.(type) {
    38  	case ReaderSeekerCloser:
    39  		return v.IsSeeker()
    40  	case *ReaderSeekerCloser:
    41  		return v.IsSeeker()
    42  	case io.ReadSeeker:
    43  		return true
    44  	default:
    45  		return false
    46  	}
    47  }
    48  
    49  // Read reads from the reader up to size of p. The number of bytes read, and
    50  // error if it occurred will be returned.
    51  //
    52  // If the reader is not an io.Reader zero bytes read, and nil error will be
    53  // returned.
    54  //
    55  // Performs the same functionality as io.Reader Read
    56  func (r ReaderSeekerCloser) Read(p []byte) (int, error) {
    57  	switch t := r.r.(type) {
    58  	case io.Reader:
    59  		return t.Read(p)
    60  	}
    61  	return 0, nil
    62  }
    63  
    64  // Seek sets the offset for the next Read to offset, interpreted according to
    65  // whence: 0 means relative to the origin of the file, 1 means relative to the
    66  // current offset, and 2 means relative to the end. Seek returns the new offset
    67  // and an error, if any.
    68  //
    69  // If the ReaderSeekerCloser is not an io.Seeker nothing will be done.
    70  func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) {
    71  	switch t := r.r.(type) {
    72  	case io.Seeker:
    73  		return t.Seek(offset, whence)
    74  	}
    75  	return int64(0), nil
    76  }
    77  
    78  // IsSeeker returns if the underlying reader is also a seeker.
    79  func (r ReaderSeekerCloser) IsSeeker() bool {
    80  	_, ok := r.r.(io.Seeker)
    81  	return ok
    82  }
    83  
    84  // HasLen returns the length of the underlying reader if the value implements
    85  // the Len() int method.
    86  func (r ReaderSeekerCloser) HasLen() (int, bool) {
    87  	type lenner interface {
    88  		Len() int
    89  	}
    90  
    91  	if lr, ok := r.r.(lenner); ok {
    92  		return lr.Len(), true
    93  	}
    94  
    95  	return 0, false
    96  }
    97  
    98  // GetLen returns the length of the bytes remaining in the underlying reader.
    99  // Checks first for Len(), then io.Seeker to determine the size of the
   100  // underlying reader.
   101  //
   102  // Will return -1 if the length cannot be determined.
   103  func (r ReaderSeekerCloser) GetLen() (int64, error) {
   104  	if l, ok := r.HasLen(); ok {
   105  		return int64(l), nil
   106  	}
   107  
   108  	if s, ok := r.r.(io.Seeker); ok {
   109  		return seekerLen(s)
   110  	}
   111  
   112  	return -1, nil
   113  }
   114  
   115  // SeekerLen attempts to get the number of bytes remaining at the seeker's
   116  // current position.  Returns the number of bytes remaining or error.
   117  func SeekerLen(s io.Seeker) (int64, error) {
   118  	// Determine if the seeker is actually seekable. ReaderSeekerCloser
   119  	// hides the fact that a io.Readers might not actually be seekable.
   120  	switch v := s.(type) {
   121  	case ReaderSeekerCloser:
   122  		return v.GetLen()
   123  	case *ReaderSeekerCloser:
   124  		return v.GetLen()
   125  	}
   126  
   127  	return seekerLen(s)
   128  }
   129  
   130  func seekerLen(s io.Seeker) (int64, error) {
   131  	curOffset, err := s.Seek(0, sdkio.SeekCurrent)
   132  	if err != nil {
   133  		return 0, err
   134  	}
   135  
   136  	endOffset, err := s.Seek(0, sdkio.SeekEnd)
   137  	if err != nil {
   138  		return 0, err
   139  	}
   140  
   141  	_, err = s.Seek(curOffset, sdkio.SeekStart)
   142  	if err != nil {
   143  		return 0, err
   144  	}
   145  
   146  	return endOffset - curOffset, nil
   147  }
   148  
   149  // Close closes the ReaderSeekerCloser.
   150  //
   151  // If the ReaderSeekerCloser is not an io.Closer nothing will be done.
   152  func (r ReaderSeekerCloser) Close() error {
   153  	switch t := r.r.(type) {
   154  	case io.Closer:
   155  		return t.Close()
   156  	}
   157  	return nil
   158  }
   159  
   160  // A WriteAtBuffer provides a in memory buffer supporting the io.WriterAt interface
   161  // Can be used with the s3manager.Downloader to download content to a buffer
   162  // in memory. Safe to use concurrently.
   163  type WriteAtBuffer struct {
   164  	buf []byte
   165  	m   sync.Mutex
   166  
   167  	// GrowthCoeff defines the growth rate of the internal buffer. By
   168  	// default, the growth rate is 1, where expanding the internal
   169  	// buffer will allocate only enough capacity to fit the new expected
   170  	// length.
   171  	GrowthCoeff float64
   172  }
   173  
   174  // NewWriteAtBuffer creates a WriteAtBuffer with an internal buffer
   175  // provided by buf.
   176  func NewWriteAtBuffer(buf []byte) *WriteAtBuffer {
   177  	return &WriteAtBuffer{buf: buf}
   178  }
   179  
   180  // WriteAt writes a slice of bytes to a buffer starting at the position provided
   181  // The number of bytes written will be returned, or error. Can overwrite previous
   182  // written slices if the write ats overlap.
   183  func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) {
   184  	pLen := len(p)
   185  	expLen := pos + int64(pLen)
   186  	b.m.Lock()
   187  	defer b.m.Unlock()
   188  	if int64(len(b.buf)) < expLen {
   189  		if int64(cap(b.buf)) < expLen {
   190  			if b.GrowthCoeff < 1 {
   191  				b.GrowthCoeff = 1
   192  			}
   193  			newBuf := make([]byte, expLen, int64(b.GrowthCoeff*float64(expLen)))
   194  			copy(newBuf, b.buf)
   195  			b.buf = newBuf
   196  		}
   197  		b.buf = b.buf[:expLen]
   198  	}
   199  	copy(b.buf[pos:], p)
   200  	return pLen, nil
   201  }
   202  
   203  // Bytes returns a slice of bytes written to the buffer.
   204  func (b *WriteAtBuffer) Bytes() []byte {
   205  	b.m.Lock()
   206  	defer b.m.Unlock()
   207  	return b.buf
   208  }
   209  
   210  // MultiCloser is a utility to close multiple io.Closers within a single
   211  // statement.
   212  type MultiCloser []io.Closer
   213  
   214  // Close closes all of the io.Closers making up the MultiClosers. Any
   215  // errors that occur while closing will be returned in the order they
   216  // occur.
   217  func (m MultiCloser) Close() error {
   218  	var errs errors
   219  	for _, c := range m {
   220  		err := c.Close()
   221  		if err != nil {
   222  			errs = append(errs, err)
   223  		}
   224  	}
   225  	if len(errs) != 0 {
   226  		return errs
   227  	}
   228  
   229  	return nil
   230  }
   231  
   232  type errors []error
   233  
   234  func (es errors) Error() string {
   235  	var parts []string
   236  	for _, e := range es {
   237  		parts = append(parts, e.Error())
   238  	}
   239  
   240  	return strings.Join(parts, "\n")
   241  }
   242  
   243  // CopySeekableBody copies the seekable body to an io.Writer
   244  func CopySeekableBody(dst io.Writer, src io.ReadSeeker) (int64, error) {
   245  	curPos, err := src.Seek(0, sdkio.SeekCurrent)
   246  	if err != nil {
   247  		return 0, err
   248  	}
   249  
   250  	// copy errors may be assumed to be from the body.
   251  	n, err := io.Copy(dst, src)
   252  	if err != nil {
   253  		return n, err
   254  	}
   255  
   256  	// seek back to the first position after reading to reset
   257  	// the body for transmission.
   258  	_, err = src.Seek(curPos, sdkio.SeekStart)
   259  	if err != nil {
   260  		return n, err
   261  	}
   262  
   263  	return n, nil
   264  }