github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/tlio/writers.go (about)

     1  package tlio
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"sync/atomic"
     7  	"testing"
     8  
     9  	"github.com/nikandfor/errors"
    10  
    11  	"github.com/nikandfor/tlog"
    12  	"github.com/nikandfor/tlog/tlwire"
    13  )
    14  
    15  type (
    16  	MultiWriter []io.Writer
    17  
    18  	ReWriter struct {
    19  		io.Writer
    20  		io.Closer
    21  
    22  		Open func(io.Writer, error) (io.Writer, error)
    23  	}
    24  
    25  	// DeLabels removes repeating Labels from events.
    26  	DeLabels struct {
    27  		io.Writer
    28  
    29  		d tlwire.Decoder
    30  		e tlwire.Encoder
    31  
    32  		b, ls []byte
    33  	}
    34  
    35  	TailWriter struct {
    36  		io.Writer
    37  		n int
    38  
    39  		i   int
    40  		buf [][]byte
    41  	}
    42  
    43  	HeadWriter struct {
    44  		io.Writer
    45  		N int
    46  	}
    47  
    48  	// CountingIODiscard discards data but counts writes and bytes.
    49  	// It's safe to use simultaneously (atomic operations are used).
    50  	CountingIODiscard struct {
    51  		Bytes, Writes atomic.Int64
    52  	}
    53  
    54  	WriterFunc func(p []byte) (int, error)
    55  
    56  	// base interfaces
    57  
    58  	Flusher interface {
    59  		Flush() error
    60  	}
    61  
    62  	FlusherNoError interface {
    63  		Flush()
    64  	}
    65  
    66  	NopCloser struct {
    67  		io.Reader
    68  		io.Writer
    69  	}
    70  
    71  	WriteCloser struct {
    72  		io.Writer
    73  		io.Closer
    74  	}
    75  
    76  	WriteFlusher struct {
    77  		io.Writer
    78  		Flusher
    79  	}
    80  
    81  	wrapFlusher struct {
    82  		FlusherNoError
    83  	}
    84  )
    85  
    86  func NewMultiWriter(ws ...io.Writer) (w MultiWriter) {
    87  	return w.Append(ws...)
    88  }
    89  
    90  func (w MultiWriter) Append(ws ...io.Writer) MultiWriter {
    91  	w = make(MultiWriter, 0, len(ws))
    92  
    93  	for _, s := range ws {
    94  		if s == nil {
    95  			continue
    96  		}
    97  
    98  		if tee, ok := s.(MultiWriter); ok {
    99  			w = append(w, tee...)
   100  		} else {
   101  			w = append(w, s)
   102  		}
   103  	}
   104  
   105  	return w
   106  }
   107  
   108  func (w MultiWriter) Write(p []byte) (n int, err error) {
   109  	for i, w := range w {
   110  		m, e := w.Write(p)
   111  
   112  		if i == 0 {
   113  			n = m
   114  		}
   115  
   116  		if err == nil {
   117  			err = e
   118  		}
   119  	}
   120  
   121  	return
   122  }
   123  
   124  func (w MultiWriter) Close() (err error) {
   125  	for _, w := range w {
   126  		c, ok := w.(io.Closer)
   127  		if !ok {
   128  			continue
   129  		}
   130  
   131  		e := c.Close()
   132  		if err == nil {
   133  			err = e
   134  		}
   135  	}
   136  
   137  	return
   138  }
   139  
   140  func (NopCloser) Close() error { return nil }
   141  
   142  func (c NopCloser) Fd() uintptr {
   143  	return Fd(c.Writer)
   144  }
   145  
   146  func (w *CountingIODiscard) ReportDisk(b *testing.B) {
   147  	b.ReportMetric(float64(w.Bytes.Load())/float64(b.N), "disk_B/op")
   148  }
   149  
   150  func (w *CountingIODiscard) Write(p []byte) (int, error) {
   151  	w.Writes.Add(1)
   152  	w.Bytes.Add(int64(len(p)))
   153  
   154  	return len(p), nil
   155  }
   156  
   157  func NewReWriter(open func(io.Writer, error) (io.Writer, error)) *ReWriter {
   158  	return &ReWriter{
   159  		Open: open,
   160  	}
   161  }
   162  
   163  func (w *ReWriter) Write(p []byte) (n int, err error) {
   164  	if w.Writer != nil {
   165  		n, err = w.Writer.Write(p)
   166  		if err == nil {
   167  			return n, nil
   168  		}
   169  	}
   170  
   171  	err = w.open()
   172  	if err != nil {
   173  		return
   174  	}
   175  
   176  	n, err = w.Writer.Write(p)
   177  	if err != nil {
   178  		return
   179  	}
   180  
   181  	return
   182  }
   183  
   184  func (w *ReWriter) open() (err error) {
   185  	w.Writer, err = w.Open(w.Writer, err)
   186  	if err != nil {
   187  		return errors.Wrap(err, "open")
   188  	}
   189  
   190  	w.Closer, _ = w.Writer.(io.Closer)
   191  
   192  	return nil
   193  }
   194  
   195  func (w *ReWriter) Close() error {
   196  	if w.Closer == nil {
   197  		return nil
   198  	}
   199  
   200  	return w.Closer.Close()
   201  }
   202  
   203  func NewDeLabels(w io.Writer) *DeLabels {
   204  	return &DeLabels{
   205  		Writer: w,
   206  	}
   207  }
   208  
   209  func (w *DeLabels) Write(p []byte) (i int, err error) {
   210  	tag, els, i := w.d.Tag(p, i)
   211  	if tag != tlwire.Map {
   212  		return i, errors.New("map expected")
   213  	}
   214  
   215  	gst := i
   216  
   217  	var st int
   218  	var sub int64
   219  	for el := 0; els == -1 || el < int(els); el++ {
   220  		if els == -1 && w.d.Break(p, &i) {
   221  			break
   222  		}
   223  
   224  		st = i
   225  
   226  		_, i = w.d.Bytes(p, i)
   227  		_, sub, i = w.d.SkipTag(p, i)
   228  
   229  		if sub == tlog.WireLabel {
   230  			break
   231  		}
   232  	}
   233  
   234  	if !bytes.Equal(w.ls, p[st:i]) {
   235  		w.ls = append(w.ls[:0], p[st:i]...)
   236  
   237  		return w.Writer.Write(p)
   238  	}
   239  
   240  	w.b = w.b[:0]
   241  
   242  	if els != -1 {
   243  		w.b = w.e.AppendMap(w.b, int(els-1))
   244  	} else {
   245  		gst = 0
   246  	}
   247  
   248  	w.b = append(w.b, p[gst:st]...)
   249  	w.b = append(w.b, p[i:]...)
   250  
   251  	i, err = w.Writer.Write(w.b)
   252  	if err != nil {
   253  		return i, err
   254  	}
   255  
   256  	return len(p), nil
   257  }
   258  
   259  func (w *DeLabels) Unwrap() interface{} {
   260  	return w.Writer
   261  }
   262  
   263  func NewTailWriter(w io.Writer, n int) *TailWriter {
   264  	return &TailWriter{
   265  		Writer: w,
   266  		n:      n,
   267  		buf:    make([][]byte, n),
   268  	}
   269  }
   270  
   271  func (w *TailWriter) Write(p []byte) (n int, err error) {
   272  	i := w.i % w.n
   273  	w.buf[i] = append(w.buf[i][:0], p...)
   274  
   275  	w.i++
   276  
   277  	return len(p), nil
   278  }
   279  
   280  func (w *TailWriter) Flush() (err error) {
   281  	for i := w.i; i < w.i+w.n; i++ {
   282  		b := w.buf[i%w.n]
   283  
   284  		if len(b) == 0 {
   285  			continue
   286  		}
   287  
   288  		_, err = w.Writer.Write(b)
   289  		if err != nil {
   290  			return err
   291  		}
   292  
   293  		w.buf[i%w.n] = b[:0]
   294  	}
   295  
   296  	if f, ok := w.Writer.(Flusher); ok {
   297  		return f.Flush()
   298  	}
   299  
   300  	return nil
   301  }
   302  
   303  func (w *TailWriter) Unwrap() interface{} {
   304  	return w.Writer
   305  }
   306  
   307  func NewHeadWriter(w io.Writer, n int) *HeadWriter {
   308  	return &HeadWriter{
   309  		Writer: w,
   310  		N:      n,
   311  	}
   312  }
   313  
   314  func (w *HeadWriter) Write(p []byte) (int, error) {
   315  	if w.N > 0 {
   316  		w.N--
   317  
   318  		return w.Writer.Write(p)
   319  	}
   320  
   321  	return len(p), nil
   322  }
   323  
   324  func (w *HeadWriter) Unwrap() interface{} {
   325  	return w.Writer
   326  }
   327  
   328  func (w WriterFunc) Write(p []byte) (int, error) { return w(p) }
   329  
   330  func WrapFlusherNoError(f FlusherNoError) Flusher {
   331  	return wrapFlusher{FlusherNoError: f}
   332  }
   333  
   334  func (f wrapFlusher) Flush() error {
   335  	f.FlusherNoError.Flush()
   336  	return nil
   337  }
   338  
   339  func Fd(f interface{}) uintptr {
   340  	const ffff = ^uintptr(0)
   341  
   342  	if f == nil {
   343  		return ffff
   344  	}
   345  
   346  	switch f := f.(type) {
   347  	case interface{ Fd() uintptr }:
   348  		return f.Fd()
   349  	case interface{ Fd() int }:
   350  		return uintptr(f.Fd())
   351  	}
   352  
   353  	return ffff
   354  }