package buffer import ( "io" "sync" "time" ) var _ io.WriteCloser = (*DelayedBuffer)(nil) // DelayedBuffer is the buffer that holds items until either the buffer filled or a specified time limit is reached type DelayedBuffer struct { mu sync.Mutex maxWait time.Duration flushTime time.Time buffer chan []byte ticker *time.Ticker w io.Writer err error } func NewDelayedBuffer(size int, maxWait time.Duration, w io.Writer) *DelayedBuffer { b := &DelayedBuffer{ buffer: make(chan []byte, size), ticker: time.NewTicker(maxWait), w: w, flushTime: time.Now(), maxWait: maxWait, } b.loop() return b } func (b *DelayedBuffer) loop() { go func() { for range b.ticker.C { b.mu.Lock() if time.Since(b.flushTime) > b.maxWait { b.flush() } b.mu.Unlock() } }() } func (b *DelayedBuffer) flush() { bufLen := len(b.buffer) if bufLen > 0 { tmp := make([][]byte, bufLen) for i := 0; i < bufLen; i++ { tmp[i] = <-b.buffer } for _, t := range tmp { _, b.err = b.w.Write(t) } b.flushTime = time.Now() } } func (b *DelayedBuffer) Put(items ...[]byte) { b.mu.Lock() for _, item := range items { select { case b.buffer <- item: default: b.flush() b.buffer <- item } } b.mu.Unlock() } func (b *DelayedBuffer) Close() error { b.mu.Lock() b.flush() close(b.buffer) b.ticker.Stop() b.mu.Unlock() return b.err } func (b *DelayedBuffer) Write(data []byte) (int, error) { b.Put(data) return len(data), b.err }