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 }