Path: blob/main/components/supervisor/pkg/terminal/ring-buffer.go
2500 views
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.1// Licensed under the GNU Affero General Public License (AGPL).2// See License.AGPL.txt in the project root for license information.34package terminal56import "golang.org/x/xerrors"78// RingBuffer implements a ring buffer. It is a fixed size,9// and new writes overwrite older data, such that for a buffer10// of size N, for any amount of writes, only the last N bytes11// are retained.12type RingBuffer struct {13data []byte14size int6415writeCursor int6416written int6417}1819// NewRingBuffer creates a new buffer of a given size. The size20// must be greater than 0.21func NewRingBuffer(size int64) (*RingBuffer, error) {22if size <= 0 {23return nil, xerrors.Errorf("Size must be positive")24}2526b := &RingBuffer{27size: size,28data: make([]byte, size),29}30return b, nil31}3233// Write writes up to len(buf) bytes to the internal ring,34// overriding older data if necessary.35func (b *RingBuffer) Write(buf []byte) (int, error) {36// Account for total bytes written37n := len(buf)38b.written += int64(n)3940// If the buffer is larger than ours, then we only care41// about the last size bytes anyways42if int64(n) > b.size {43buf = buf[int64(n)-b.size:]44}4546// Copy in place47remain := b.size - b.writeCursor48copy(b.data[b.writeCursor:], buf)49if int64(len(buf)) > remain {50copy(b.data, buf[remain:])51}5253// Update location of the cursor54b.writeCursor = ((b.writeCursor + int64(len(buf))) % b.size)55return n, nil56}5758// Size returns the size of the buffer.59func (b *RingBuffer) Size() int64 {60return b.size61}6263// TotalWritten provides the total number of bytes written.64func (b *RingBuffer) TotalWritten() int64 {65return b.written66}6768// Bytes provides a slice of the bytes written. This69// slice should not be written to.70func (b *RingBuffer) Bytes() []byte {71switch {72case b.written >= b.size && b.writeCursor == 0:73return b.data74case b.written > b.size:75out := make([]byte, b.size)76copy(out, b.data[b.writeCursor:])77copy(out[b.size-b.writeCursor:], b.data[:b.writeCursor])78return out79default:80return b.data[:b.writeCursor]81}82}8384// Reset resets the buffer so it has no content.85func (b *RingBuffer) Reset() {86b.writeCursor = 087b.written = 088}8990// String returns the contents of the buffer as a string.91func (b *RingBuffer) String() string {92return string(b.Bytes())93}949596