github.com/minio/minio-go/v6@v6.0.57/hook-reader.go (about) 1 /* 2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage 3 * Copyright 2015-2017 MinIO, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package minio 19 20 import ( 21 "fmt" 22 "io" 23 ) 24 25 // hookReader hooks additional reader in the source stream. It is 26 // useful for making progress bars. Second reader is appropriately 27 // notified about the exact number of bytes read from the primary 28 // source on each Read operation. 29 type hookReader struct { 30 source io.Reader 31 hook io.Reader 32 } 33 34 // Seek implements io.Seeker. Seeks source first, and if necessary 35 // seeks hook if Seek method is appropriately found. 36 func (hr *hookReader) Seek(offset int64, whence int) (n int64, err error) { 37 // Verify for source has embedded Seeker, use it. 38 sourceSeeker, ok := hr.source.(io.Seeker) 39 if ok { 40 n, err = sourceSeeker.Seek(offset, whence) 41 if err != nil { 42 return 0, err 43 } 44 } 45 46 // Verify if hook has embedded Seeker, use it. 47 hookSeeker, ok := hr.hook.(io.Seeker) 48 if ok { 49 var m int64 50 m, err = hookSeeker.Seek(offset, whence) 51 if err != nil { 52 return 0, err 53 } 54 if n != m { 55 return 0, fmt.Errorf("hook seeker seeked %d bytes, expected source %d bytes", m, n) 56 } 57 } 58 return n, nil 59 } 60 61 // Read implements io.Reader. Always reads from the source, the return 62 // value 'n' number of bytes are reported through the hook. Returns 63 // error for all non io.EOF conditions. 64 func (hr *hookReader) Read(b []byte) (n int, err error) { 65 n, err = hr.source.Read(b) 66 if err != nil && err != io.EOF { 67 return n, err 68 } 69 // Progress the hook with the total read bytes from the source. 70 if _, herr := hr.hook.Read(b[:n]); herr != nil { 71 if herr != io.EOF { 72 return n, herr 73 } 74 } 75 return n, err 76 } 77 78 // newHook returns a io.ReadSeeker which implements hookReader that 79 // reports the data read from the source to the hook. 80 func newHook(source, hook io.Reader) io.Reader { 81 if hook == nil { 82 return source 83 } 84 return &hookReader{source, hook} 85 }