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

     1  package tlio
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"sync/atomic"
     7  	"testing"
     8  
     9  	"tlog.app/go/errors"
    10  
    11  	"tlog.app/go/tlog"
    12  	"tlog.app/go/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  	SandwichWriter struct {
    55  		io.Writer
    56  		sandwichFilling
    57  	}
    58  
    59  	sandwichFilling struct {
    60  		io.Writer
    61  		n int
    62  	}
    63  
    64  	WriterFunc func(p []byte) (int, error)
    65  
    66  	// base interfaces
    67  
    68  	Flusher interface {
    69  		Flush() error
    70  	}
    71  
    72  	FlusherNoError interface {
    73  		Flush()
    74  	}
    75  
    76  	NopCloser struct {
    77  		io.Reader
    78  		io.Writer
    79  	}
    80  
    81  	WriteCloser struct {
    82  		io.Writer
    83  		io.Closer
    84  	}
    85  
    86  	WriteFlusher struct {
    87  		io.Writer
    88  		Flusher
    89  	}
    90  
    91  	wrapFlusher struct {
    92  		FlusherNoError
    93  	}
    94  )
    95  
    96  func NewMultiWriter(ws ...io.Writer) (w MultiWriter) {
    97  	return w.Append(ws...)
    98  }
    99  
   100  func (w MultiWriter) Append(ws ...io.Writer) MultiWriter {
   101  	w = make(MultiWriter, 0, len(ws))
   102  
   103  	for _, s := range ws {
   104  		if s == nil {
   105  			continue
   106  		}
   107  
   108  		if tee, ok := s.(MultiWriter); ok {
   109  			w = append(w, tee...)
   110  		} else {
   111  			w = append(w, s)
   112  		}
   113  	}
   114  
   115  	return w
   116  }
   117  
   118  func (w MultiWriter) Write(p []byte) (n int, err error) {
   119  	for i, w := range w {
   120  		m, e := w.Write(p)
   121  
   122  		if i == 0 {
   123  			n = m
   124  		}
   125  
   126  		if err == nil {
   127  			err = e
   128  		}
   129  	}
   130  
   131  	return
   132  }
   133  
   134  func (w MultiWriter) Close() (err error) {
   135  	for _, w := range w {
   136  		c, ok := w.(io.Closer)
   137  		if !ok {
   138  			continue
   139  		}
   140  
   141  		e := c.Close()
   142  		if err == nil {
   143  			err = e
   144  		}
   145  	}
   146  
   147  	return
   148  }
   149  
   150  func (NopCloser) Close() error { return nil }
   151  
   152  func (c NopCloser) Fd() uintptr {
   153  	return Fd(c.Writer)
   154  }
   155  
   156  func (w *CountingIODiscard) ReportDisk(b *testing.B) {
   157  	b.ReportMetric(float64(w.Bytes.Load())/float64(b.N), "disk_B/op")
   158  }
   159  
   160  func (w *CountingIODiscard) Write(p []byte) (int, error) {
   161  	w.Writes.Add(1)
   162  	w.Bytes.Add(int64(len(p)))
   163  
   164  	return len(p), nil
   165  }
   166  
   167  func NewReWriter(open func(io.Writer, error) (io.Writer, error)) *ReWriter {
   168  	return &ReWriter{
   169  		Open: open,
   170  	}
   171  }
   172  
   173  func (w *ReWriter) Write(p []byte) (n int, err error) {
   174  	if w.Writer != nil {
   175  		n, err = w.Writer.Write(p)
   176  		if err == nil {
   177  			return n, nil
   178  		}
   179  	}
   180  
   181  	err = w.open()
   182  	if err != nil {
   183  		return
   184  	}
   185  
   186  	n, err = w.Writer.Write(p)
   187  	if err != nil {
   188  		return
   189  	}
   190  
   191  	return
   192  }
   193  
   194  func (w *ReWriter) open() (err error) {
   195  	w.Writer, err = w.Open(w.Writer, err)
   196  	if err != nil {
   197  		return errors.Wrap(err, "open")
   198  	}
   199  
   200  	w.Closer, _ = w.Writer.(io.Closer)
   201  
   202  	return nil
   203  }
   204  
   205  func (w *ReWriter) Close() error {
   206  	if w.Closer == nil {
   207  		return nil
   208  	}
   209  
   210  	return w.Closer.Close()
   211  }
   212  
   213  func NewDeLabels(w io.Writer) *DeLabels {
   214  	return &DeLabels{
   215  		Writer: w,
   216  	}
   217  }
   218  
   219  func (w *DeLabels) Write(p []byte) (i int, err error) {
   220  	tag, els, i := w.d.Tag(p, i)
   221  	if tag != tlwire.Map {
   222  		return i, errors.New("map expected")
   223  	}
   224  
   225  	gst := i
   226  
   227  	var st int
   228  	var sub int64
   229  	for el := 0; els == -1 || el < int(els); el++ {
   230  		if els == -1 && w.d.Break(p, &i) {
   231  			break
   232  		}
   233  
   234  		st = i
   235  
   236  		_, i = w.d.Bytes(p, i)
   237  		_, sub, i = w.d.SkipTag(p, i)
   238  
   239  		if sub == tlog.WireLabel {
   240  			break
   241  		}
   242  	}
   243  
   244  	if !bytes.Equal(w.ls, p[st:i]) {
   245  		w.ls = append(w.ls[:0], p[st:i]...)
   246  
   247  		return w.Writer.Write(p)
   248  	}
   249  
   250  	w.b = w.b[:0]
   251  
   252  	if els != -1 {
   253  		w.b = w.e.AppendMap(w.b, int(els-1))
   254  	} else {
   255  		gst = 0
   256  	}
   257  
   258  	w.b = append(w.b, p[gst:st]...)
   259  	w.b = append(w.b, p[i:]...)
   260  
   261  	i, err = w.Writer.Write(w.b)
   262  	if err != nil {
   263  		return i, err
   264  	}
   265  
   266  	return len(p), nil
   267  }
   268  
   269  func (w *DeLabels) Unwrap() interface{} {
   270  	return w.Writer
   271  }
   272  
   273  func NewTailWriter(w io.Writer, n int) *TailWriter {
   274  	return &TailWriter{
   275  		Writer: w,
   276  		n:      n,
   277  		buf:    make([][]byte, n),
   278  	}
   279  }
   280  
   281  func (w *TailWriter) Write(p []byte) (n int, err error) {
   282  	i := w.i % w.n
   283  	w.buf[i] = append(w.buf[i][:0], p...)
   284  
   285  	w.i++
   286  
   287  	return len(p), nil
   288  }
   289  
   290  func (w *TailWriter) Flush() (err error) {
   291  	for i := w.i; i < w.i+w.n; i++ {
   292  		b := w.buf[i%w.n]
   293  
   294  		if len(b) == 0 {
   295  			continue
   296  		}
   297  
   298  		_, err = w.Writer.Write(b)
   299  		if err != nil {
   300  			return err
   301  		}
   302  
   303  		w.buf[i%w.n] = b[:0]
   304  	}
   305  
   306  	if f, ok := w.Writer.(Flusher); ok {
   307  		return f.Flush()
   308  	}
   309  
   310  	return nil
   311  }
   312  
   313  func (w *TailWriter) Unwrap() interface{} {
   314  	return w.Writer
   315  }
   316  
   317  func NewHeadWriter(w io.Writer, n int) *HeadWriter {
   318  	return &HeadWriter{
   319  		Writer: w,
   320  		N:      n,
   321  	}
   322  }
   323  
   324  func (w *HeadWriter) Write(p []byte) (int, error) {
   325  	if w.N > 0 {
   326  		w.N--
   327  
   328  		return w.Writer.Write(p)
   329  	}
   330  
   331  	return len(p), nil
   332  }
   333  
   334  func (w *HeadWriter) Unwrap() interface{} {
   335  	return w.Writer
   336  }
   337  
   338  func NewSandwichWriter(filling io.Writer) *SandwichWriter {
   339  	return &SandwichWriter{
   340  		sandwichFilling: sandwichFilling{
   341  			Writer: filling,
   342  		},
   343  	}
   344  }
   345  
   346  func (w *SandwichWriter) Write(p []byte) (int, error) {
   347  	w.n = -1
   348  
   349  	n, err := w.Writer.Write(p)
   350  
   351  	if w.n != -1 {
   352  		n = w.n
   353  	}
   354  
   355  	return n, err
   356  }
   357  
   358  func (w *sandwichFilling) Write(p []byte) (int, error) {
   359  	n, err := w.Writer.Write(p)
   360  	w.n = n
   361  
   362  	return n, err
   363  }
   364  
   365  func (w *SandwichWriter) Inner() io.Writer {
   366  	if c, ok := w.sandwichFilling.Writer.(io.Closer); ok {
   367  		return WriteCloser{
   368  			Writer: &w.sandwichFilling,
   369  			Closer: c,
   370  		}
   371  	}
   372  
   373  	return &w.sandwichFilling
   374  }
   375  
   376  func (w *SandwichWriter) Unwrap() interface{} {
   377  	return w.Writer
   378  }
   379  
   380  func (w WriterFunc) Write(p []byte) (int, error) { return w(p) }
   381  
   382  func WrapFlusherNoError(f FlusherNoError) Flusher {
   383  	return wrapFlusher{FlusherNoError: f}
   384  }
   385  
   386  func (f wrapFlusher) Flush() error {
   387  	f.FlusherNoError.Flush()
   388  	return nil
   389  }
   390  
   391  func Fd(f interface{}) uintptr {
   392  	const ffff = ^uintptr(0)
   393  
   394  	if f == nil {
   395  		return ffff
   396  	}
   397  
   398  	switch f := f.(type) {
   399  	case interface{ Fd() uintptr }:
   400  		return f.Fd()
   401  	case interface{ Fd() int }:
   402  		return uintptr(f.Fd())
   403  	}
   404  
   405  	return ffff
   406  }