github.com/bhojpur/cache@v0.0.4/pkg/ioutils/readers.go (about) 1 package ioutils 2 3 // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved. 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 import ( 24 "context" 25 "io" 26 27 // make sure crypto.SHA256, crypto.sha512 and crypto.SHA384 are registered 28 _ "crypto/sha256" 29 _ "crypto/sha512" 30 ) 31 32 // ReadCloserWrapper wraps an io.Reader, and implements an io.ReadCloser 33 // It calls the given callback function when closed. It should be constructed 34 // with NewReadCloserWrapper 35 type ReadCloserWrapper struct { 36 io.Reader 37 closer func() error 38 } 39 40 // Close calls back the passed closer function 41 func (r *ReadCloserWrapper) Close() error { 42 return r.closer() 43 } 44 45 // NewReadCloserWrapper returns a new io.ReadCloser. 46 func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser { 47 return &ReadCloserWrapper{ 48 Reader: r, 49 closer: closer, 50 } 51 } 52 53 type readerErrWrapper struct { 54 reader io.Reader 55 closer func() 56 } 57 58 func (r *readerErrWrapper) Read(p []byte) (int, error) { 59 n, err := r.reader.Read(p) 60 if err != nil { 61 r.closer() 62 } 63 return n, err 64 } 65 66 // NewReaderErrWrapper returns a new io.Reader. 67 func NewReaderErrWrapper(r io.Reader, closer func()) io.Reader { 68 return &readerErrWrapper{ 69 reader: r, 70 closer: closer, 71 } 72 } 73 74 // OnEOFReader wraps an io.ReadCloser and a function 75 // the function will run at the end of file or close the file. 76 type OnEOFReader struct { 77 Rc io.ReadCloser 78 Fn func() 79 } 80 81 func (r *OnEOFReader) Read(p []byte) (n int, err error) { 82 n, err = r.Rc.Read(p) 83 if err == io.EOF { 84 r.runFunc() 85 } 86 return 87 } 88 89 // Close closes the file and run the function. 90 func (r *OnEOFReader) Close() error { 91 err := r.Rc.Close() 92 r.runFunc() 93 return err 94 } 95 96 func (r *OnEOFReader) runFunc() { 97 if fn := r.Fn; fn != nil { 98 fn() 99 r.Fn = nil 100 } 101 } 102 103 // cancelReadCloser wraps an io.ReadCloser with a context for cancelling read 104 // operations. 105 type cancelReadCloser struct { 106 cancel func() 107 pR *io.PipeReader // Stream to read from 108 pW *io.PipeWriter 109 } 110 111 // NewCancelReadCloser creates a wrapper that closes the ReadCloser when the 112 // context is cancelled. The returned io.ReadCloser must be closed when it is 113 // no longer needed. 114 func NewCancelReadCloser(ctx context.Context, in io.ReadCloser) io.ReadCloser { 115 pR, pW := io.Pipe() 116 117 // Create a context used to signal when the pipe is closed 118 doneCtx, cancel := context.WithCancel(context.Background()) 119 120 p := &cancelReadCloser{ 121 cancel: cancel, 122 pR: pR, 123 pW: pW, 124 } 125 126 go func() { 127 _, err := io.Copy(pW, in) 128 select { 129 case <-ctx.Done(): 130 // If the context was closed, p.closeWithError 131 // was already called. Calling it again would 132 // change the error that Read returns. 133 default: 134 p.closeWithError(err) 135 } 136 in.Close() 137 }() 138 go func() { 139 for { 140 select { 141 case <-ctx.Done(): 142 p.closeWithError(ctx.Err()) 143 case <-doneCtx.Done(): 144 return 145 } 146 } 147 }() 148 149 return p 150 } 151 152 // Read wraps the Read method of the pipe that provides data from the wrapped 153 // ReadCloser. 154 func (p *cancelReadCloser) Read(buf []byte) (n int, err error) { 155 return p.pR.Read(buf) 156 } 157 158 // closeWithError closes the wrapper and its underlying reader. It will 159 // cause future calls to Read to return err. 160 func (p *cancelReadCloser) closeWithError(err error) { 161 p.pW.CloseWithError(err) 162 p.cancel() 163 } 164 165 // Close closes the wrapper its underlying reader. It will cause 166 // future calls to Read to return io.EOF. 167 func (p *cancelReadCloser) Close() error { 168 p.closeWithError(io.EOF) 169 return nil 170 }