mirror of
https://github.com/diamondburned/cchat-gtk.git
synced 2024-11-01 03:54:16 +00:00
43 lines
910 B
Go
43 lines
910 B
Go
|
package attachment
|
||
|
|
||
|
import (
|
||
|
"io"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
)
|
||
|
|
||
|
type Open = func() (io.ReadCloser, error)
|
||
|
|
||
|
// ReusableReader provides an API which allows a reader to be used multiple
|
||
|
// times. It is NOT thread-safe to use.
|
||
|
type ReusableReader struct {
|
||
|
open func() (io.ReadCloser, error)
|
||
|
src io.ReadCloser
|
||
|
}
|
||
|
|
||
|
var _ io.Reader = (*ReusableReader)(nil)
|
||
|
|
||
|
// NewReusableReader creates a new reader that is reusable after a read failure
|
||
|
// or a close. The given open() callback MUST be reproducible.
|
||
|
func NewReusableReader(open Open) *ReusableReader {
|
||
|
return &ReusableReader{open, nil}
|
||
|
}
|
||
|
|
||
|
func (r *ReusableReader) Read(b []byte) (int, error) {
|
||
|
if r.src == nil {
|
||
|
o, err := r.open()
|
||
|
if err != nil {
|
||
|
return 0, errors.Wrap(err, "Failed to open reader")
|
||
|
}
|
||
|
r.src = o
|
||
|
}
|
||
|
|
||
|
n, err := r.src.Read(b)
|
||
|
if err != nil { // err could be EOF or anything unexpected
|
||
|
r.src.Close()
|
||
|
r.src = nil
|
||
|
}
|
||
|
|
||
|
return n, err
|
||
|
}
|