mirror of
https://github.com/ultrasn0w/huso.git
synced 2025-12-13 23:09:52 +01:00
106 lines
2.3 KiB
Go
106 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// RingBuf implements an indefinitely writable circular buffer with a fixed size. Old data is overridden if write circle loops. Somewhat threadsafe.
|
|
type RingBuf struct {
|
|
sync.RWMutex
|
|
data []byte
|
|
writePos int
|
|
written int
|
|
loop bool
|
|
}
|
|
|
|
// NewRingBuf initializes a new RingBuf with a fixed size > 0
|
|
func NewRingBuf(size int) *RingBuf {
|
|
if size <= 0 {
|
|
return nil
|
|
}
|
|
rb := &RingBuf{
|
|
data: make([]byte, size),
|
|
writePos: 0,
|
|
written: 0,
|
|
loop: false,
|
|
}
|
|
return rb
|
|
}
|
|
|
|
func (rb *RingBuf) WriteLine(in string) (int, error) {
|
|
return rb.Write([]byte(fmt.Sprintf("[%s]: %s\n", time.Now().Format("2006-01-02 15:04:05"), in)))
|
|
}
|
|
|
|
func (rb *RingBuf) WriteError(err error) (int, error) {
|
|
return rb.Write([]byte(fmt.Sprintf("[%s]: ⚠️ %s\n", time.Now().Format("2006-01-02 15:04:05"), err.Error())))
|
|
}
|
|
|
|
// Write writes all data from input buf to RingBuf, overriding looped data
|
|
func (rb *RingBuf) Write(buf []byte) (int, error) {
|
|
rb.Lock()
|
|
defer rb.Unlock()
|
|
|
|
inLen := len(buf)
|
|
bufLen := len(rb.data)
|
|
|
|
if !rb.loop && rb.written < bufLen {
|
|
rb.written = rb.written + inLen
|
|
rb.loop = rb.written >= bufLen
|
|
}
|
|
|
|
// throw away bytes which would get looped over if input bigger than data
|
|
if inLen > bufLen {
|
|
buf = buf[inLen-bufLen:]
|
|
}
|
|
|
|
// Copy to data field
|
|
bytesToEnd := bufLen - rb.writePos
|
|
copy(rb.data[rb.writePos:], buf)
|
|
if len(buf) > bytesToEnd {
|
|
copy(rb.data, buf[bytesToEnd:])
|
|
}
|
|
// Move writePos
|
|
rb.writePos = ((rb.writePos + len(buf)) % bufLen)
|
|
return inLen, nil
|
|
}
|
|
|
|
// Size returns the maximum size of the RingBuf
|
|
func (rb *RingBuf) Size() int {
|
|
return len(rb.data)
|
|
}
|
|
|
|
// Bytes returns content of RingBuf. DON'T WRITE TO SLICE!
|
|
func (rb *RingBuf) Bytes() []byte {
|
|
rb.RLock()
|
|
defer rb.RUnlock()
|
|
|
|
bufLen := len(rb.data)
|
|
if rb.loop {
|
|
out := make([]byte, bufLen)
|
|
if rb.writePos == 0 {
|
|
copy(out, rb.data)
|
|
} else {
|
|
copy(out, rb.data[rb.writePos:])
|
|
copy(out[bufLen-rb.writePos:], rb.data[:rb.writePos])
|
|
}
|
|
return out
|
|
}
|
|
out := make([]byte, rb.writePos)
|
|
copy(out, rb.data[:rb.writePos])
|
|
return out
|
|
}
|
|
|
|
// Restart restarts RingBuf from 0
|
|
func (rb *RingBuf) Restart() {
|
|
rb.writePos = 0
|
|
rb.written = 0
|
|
rb.loop = false
|
|
}
|
|
|
|
// String returns content of RingBuf as string
|
|
func (rb *RingBuf) String() string {
|
|
return string(rb.Bytes())
|
|
}
|