1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2025-03-23 23:19:19 +02:00
pocketbase/tools/router/rereadable_read_closer.go
2024-09-29 21:09:46 +03:00

61 lines
1.4 KiB
Go

package router
import (
"bytes"
"io"
)
var (
_ io.ReadCloser = (*RereadableReadCloser)(nil)
_ Rereader = (*RereadableReadCloser)(nil)
)
// Rereader defines an interface for rewindable readers.
type Rereader interface {
Reread()
}
// RereadableReadCloser defines a wrapper around a io.ReadCloser reader
// allowing to read the original reader multiple times.
type RereadableReadCloser struct {
io.ReadCloser
copy *bytes.Buffer
active io.Reader
}
// Read implements the standard io.Reader interface.
//
// It reads up to len(b) bytes into b and at at the same time writes
// the read data into an internal bytes buffer.
//
// On EOF the r is "rewinded" to allow reading from r multiple times.
func (r *RereadableReadCloser) Read(b []byte) (int, error) {
if r.active == nil {
if r.copy == nil {
r.copy = &bytes.Buffer{}
}
r.active = io.TeeReader(r.ReadCloser, r.copy)
}
n, err := r.active.Read(b)
if err == io.EOF {
r.Reread()
}
return n, err
}
// Reread satisfies the [Rereader] interface and resets the r internal state to allow rereads.
//
// note: not named Reset to avoid conflicts with other reader interfaces.
func (r *RereadableReadCloser) Reread() {
if r.copy == nil || r.copy.Len() == 0 {
return // nothing to reset or it has been already reset
}
oldCopy := r.copy
r.copy = &bytes.Buffer{}
r.active = io.TeeReader(oldCopy, r.copy)
}