tlog.app/go/tlog@v0.23.1/tlio/readers.go (about)

     1  package tlio
     2  
     3  import (
     4  	"io"
     5  
     6  	"tlog.app/go/errors"
     7  
     8  	"tlog.app/go/tlog"
     9  )
    10  
    11  type (
    12  	ReadCloser struct {
    13  		io.Reader
    14  		io.Closer
    15  	}
    16  
    17  	Seeker interface {
    18  		Seek(off int64, whence int) (int64, error)
    19  	}
    20  
    21  	ReadSeeker interface {
    22  		io.Reader
    23  		Seeker
    24  	}
    25  
    26  	ReReader struct {
    27  		ReadSeeker
    28  
    29  		Hook func(old, cur int64)
    30  
    31  		pos int64
    32  	}
    33  
    34  	DumpReader struct {
    35  		io.Reader
    36  
    37  		tlog.Span
    38  
    39  		Pos int64
    40  	}
    41  )
    42  
    43  func NewReReader(r ReadSeeker) (*ReReader, error) {
    44  	cur, err := r.Seek(0, io.SeekCurrent)
    45  	if err != nil {
    46  		return nil, errors.Wrap(err, "seek")
    47  	}
    48  
    49  	return &ReReader{
    50  		ReadSeeker: r,
    51  
    52  		pos: cur,
    53  	}, nil
    54  }
    55  
    56  func (r *ReReader) Read(p []byte) (n int, err error) {
    57  	n, err = r.ReadSeeker.Read(p)
    58  
    59  	r.pos += int64(n)
    60  
    61  	if n == 0 && errors.Is(err, io.EOF) {
    62  		end, err := r.ReadSeeker.Seek(0, io.SeekEnd)
    63  		if err != nil {
    64  			return n, errors.Wrap(err, "seek")
    65  		}
    66  
    67  		switch {
    68  		case end < r.pos:
    69  			if r.Hook != nil {
    70  				r.Hook(r.pos, end)
    71  			}
    72  
    73  			end, err = r.ReadSeeker.Seek(0, io.SeekStart)
    74  			if err != nil {
    75  				return n, errors.Wrap(err, "seek")
    76  			}
    77  
    78  			r.pos = end
    79  		case end > r.pos:
    80  			_, err = r.ReadSeeker.Seek(r.pos, io.SeekStart)
    81  			if err != nil {
    82  				return n, errors.Wrap(err, "seek back")
    83  			}
    84  		}
    85  	}
    86  
    87  	return n, err
    88  }
    89  
    90  func (r *DumpReader) Read(p []byte) (n int, err error) {
    91  	n, err = r.Reader.Read(p)
    92  
    93  	r.Span.Printw("read", "n", n, "err", err, "p_len", len(p), "pos", r.Pos, "data", p[:n])
    94  
    95  	r.Pos += int64(n)
    96  
    97  	return
    98  }
    99  
   100  func (r *DumpReader) Close() (err error) {
   101  	c, ok := r.Reader.(io.Closer)
   102  	if ok {
   103  		err = c.Close()
   104  	}
   105  
   106  	r.Span.Printw("close", "err", err, "pos", r.Pos, "closer", ok)
   107  
   108  	return
   109  }
   110  
   111  func (r *DumpReader) Seek(off int64, whence int) (pos int64, err error) {
   112  	c, ok := r.Reader.(Seeker)
   113  	if ok {
   114  		pos, err = c.Seek(off, whence)
   115  		r.Pos = pos
   116  	}
   117  
   118  	r.Span.Printw("seek", "pos", pos, "err", err, "off", off, "whence", whence, "seeker", ok)
   119  
   120  	return
   121  }