github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/tlio/readers.go (about) 1 package tlio 2 3 import ( 4 "io" 5 6 "github.com/nikandfor/errors" 7 8 "github.com/nikandfor/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 }