aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/minio/minio-go/v7/hook-reader.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/hook-reader.go')
-rw-r--r--vendor/github.com/minio/minio-go/v7/hook-reader.go101
1 files changed, 101 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/hook-reader.go b/vendor/github.com/minio/minio-go/v7/hook-reader.go
new file mode 100644
index 0000000..07bc7db
--- /dev/null
+++ b/vendor/github.com/minio/minio-go/v7/hook-reader.go
@@ -0,0 +1,101 @@
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
18package minio
19
20import (
21 "fmt"
22 "io"
23 "sync"
24)
25
26// hookReader hooks additional reader in the source stream. It is
27// useful for making progress bars. Second reader is appropriately
28// notified about the exact number of bytes read from the primary
29// source on each Read operation.
30type hookReader struct {
31 mu sync.RWMutex
32 source io.Reader
33 hook io.Reader
34}
35
36// Seek implements io.Seeker. Seeks source first, and if necessary
37// seeks hook if Seek method is appropriately found.
38func (hr *hookReader) Seek(offset int64, whence int) (n int64, err error) {
39 hr.mu.Lock()
40 defer hr.mu.Unlock()
41
42 // Verify for source has embedded Seeker, use it.
43 sourceSeeker, ok := hr.source.(io.Seeker)
44 if ok {
45 n, err = sourceSeeker.Seek(offset, whence)
46 if err != nil {
47 return 0, err
48 }
49 }
50
51 if hr.hook != nil {
52 // Verify if hook has embedded Seeker, use it.
53 hookSeeker, ok := hr.hook.(io.Seeker)
54 if ok {
55 var m int64
56 m, err = hookSeeker.Seek(offset, whence)
57 if err != nil {
58 return 0, err
59 }
60 if n != m {
61 return 0, fmt.Errorf("hook seeker seeked %d bytes, expected source %d bytes", m, n)
62 }
63 }
64 }
65
66 return n, nil
67}
68
69// Read implements io.Reader. Always reads from the source, the return
70// value 'n' number of bytes are reported through the hook. Returns
71// error for all non io.EOF conditions.
72func (hr *hookReader) Read(b []byte) (n int, err error) {
73 hr.mu.RLock()
74 defer hr.mu.RUnlock()
75
76 n, err = hr.source.Read(b)
77 if err != nil && err != io.EOF {
78 return n, err
79 }
80 if hr.hook != nil {
81 // Progress the hook with the total read bytes from the source.
82 if _, herr := hr.hook.Read(b[:n]); herr != nil {
83 if herr != io.EOF {
84 return n, herr
85 }
86 }
87 }
88 return n, err
89}
90
91// newHook returns a io.ReadSeeker which implements hookReader that
92// reports the data read from the source to the hook.
93func newHook(source, hook io.Reader) io.Reader {
94 if hook == nil {
95 return &hookReader{source: source}
96 }
97 return &hookReader{
98 source: source,
99 hook: hook,
100 }
101}