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 }