mirror of
https://github.com/harshabose/simple_skyline_sonata.git
synced 2025-12-24 13:57:54 +08:00
Re-add tools submodule properly
This commit is contained in:
1
dependencies/tools
vendored
Submodule
1
dependencies/tools
vendored
Submodule
Submodule dependencies/tools added at d5ed322260
50
dependencies/tools/.gitignore
vendored
50
dependencies/tools/.gitignore
vendored
@@ -1,50 +0,0 @@
|
|||||||
# Binaries for programs and plugins
|
|
||||||
*.exe
|
|
||||||
*.exe~
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
|
||||||
*.test
|
|
||||||
|
|
||||||
# Output of the go coverage tool
|
|
||||||
*.out
|
|
||||||
|
|
||||||
# Go workspace file
|
|
||||||
go.work
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
vendor/
|
|
||||||
|
|
||||||
# Build directories
|
|
||||||
build/
|
|
||||||
third_party/
|
|
||||||
|
|
||||||
# Environment files
|
|
||||||
*.env
|
|
||||||
!.env.example
|
|
||||||
|
|
||||||
# macOS
|
|
||||||
.DS_Store
|
|
||||||
.DS_Store?
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Linux
|
|
||||||
*~
|
|
||||||
|
|
||||||
# IDE files
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
|
|
||||||
# Logs
|
|
||||||
*.log
|
|
||||||
logs/
|
|
||||||
7
dependencies/tools/go.mod
vendored
7
dependencies/tools/go.mod
vendored
@@ -1,7 +0,0 @@
|
|||||||
module github.com/harshabose/tools
|
|
||||||
|
|
||||||
go 1.24.1
|
|
||||||
|
|
||||||
require github.com/asticode/go-astiav v0.37.0
|
|
||||||
|
|
||||||
require github.com/asticode/go-astikit v0.42.0 // indirect
|
|
||||||
12
dependencies/tools/go.sum
vendored
12
dependencies/tools/go.sum
vendored
@@ -1,12 +0,0 @@
|
|||||||
github.com/asticode/go-astiav v0.37.0 h1:Ph4usW4lulotVvne8hqZ1JCOHX1f8ces6yVKdg+PnyQ=
|
|
||||||
github.com/asticode/go-astiav v0.37.0/go.mod h1:GI0pHw6K2/pl/o8upCtT49P/q4KCwhv/8nGLlCsZLdA=
|
|
||||||
github.com/asticode/go-astikit v0.42.0 h1:pnir/2KLUSr0527Tv908iAH6EGYYrYta132vvjXsH5w=
|
|
||||||
github.com/asticode/go-astikit v0.42.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0=
|
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
8
dependencies/tools/pkg/buffer/errors.go
vendored
8
dependencies/tools/pkg/buffer/errors.go
vendored
@@ -1,8 +0,0 @@
|
|||||||
package buffer
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrorElementUnallocated = errors.New("encountered nil in the buffer. this should not happen. check usage")
|
|
||||||
ErrorChannelBufferClose = errors.New("channel buffer has be closed. cannot perform this operation")
|
|
||||||
)
|
|
||||||
55
dependencies/tools/pkg/buffer/frame_pool.go
vendored
55
dependencies/tools/pkg/buffer/frame_pool.go
vendored
@@ -1,55 +0,0 @@
|
|||||||
//go:build cgo_enabled
|
|
||||||
|
|
||||||
package buffer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/asticode/go-astiav"
|
|
||||||
)
|
|
||||||
|
|
||||||
type framePool struct {
|
|
||||||
pool sync.Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateFramePool() Pool[*astiav.Frame] {
|
|
||||||
return &framePool{
|
|
||||||
pool: sync.Pool{
|
|
||||||
New: func() any {
|
|
||||||
return astiav.AllocFrame()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *framePool) Get() *astiav.Frame {
|
|
||||||
frame, ok := pool.pool.Get().(*astiav.Frame)
|
|
||||||
|
|
||||||
if frame == nil || !ok {
|
|
||||||
return astiav.AllocFrame()
|
|
||||||
}
|
|
||||||
return frame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *framePool) Put(frame *astiav.Frame) {
|
|
||||||
if frame == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.Unref()
|
|
||||||
pool.pool.Put(frame)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *framePool) Release() {
|
|
||||||
for {
|
|
||||||
frame, ok := pool.pool.Get().(*astiav.Frame)
|
|
||||||
if frame == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
frame.Free()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
144
dependencies/tools/pkg/buffer/limit_buffer.go
vendored
144
dependencies/tools/pkg/buffer/limit_buffer.go
vendored
@@ -1,144 +0,0 @@
|
|||||||
package buffer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChannelBuffer[T any] struct {
|
|
||||||
pool Pool[T]
|
|
||||||
bufferChannel chan T
|
|
||||||
inputBuffer chan T
|
|
||||||
closed bool
|
|
||||||
mux sync.RWMutex
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateChannelBuffer[T any](ctx context.Context, size int, pool Pool[T]) *ChannelBuffer[T] {
|
|
||||||
buffer := &ChannelBuffer[T]{
|
|
||||||
pool: pool,
|
|
||||||
bufferChannel: make(chan T, size),
|
|
||||||
inputBuffer: make(chan T, size),
|
|
||||||
closed: false,
|
|
||||||
ctx: ctx,
|
|
||||||
}
|
|
||||||
go buffer.loop()
|
|
||||||
return buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buffer *ChannelBuffer[T]) Push(ctx context.Context, element T) error {
|
|
||||||
buffer.mux.RLock()
|
|
||||||
defer buffer.mux.RUnlock()
|
|
||||||
|
|
||||||
if buffer.closed {
|
|
||||||
return errors.New("buffer closed")
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case buffer.inputBuffer <- element:
|
|
||||||
// WARN: LACKS CHECKS FOR CLOSED CHANNEL
|
|
||||||
return nil
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buffer *ChannelBuffer[T]) Pop(ctx context.Context) (T, error) {
|
|
||||||
buffer.mux.RLock()
|
|
||||||
defer buffer.mux.RUnlock()
|
|
||||||
|
|
||||||
var zero T
|
|
||||||
|
|
||||||
if buffer.closed {
|
|
||||||
return zero, errors.New("buffer closed")
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return zero, ctx.Err()
|
|
||||||
case data, ok := <-buffer.bufferChannel:
|
|
||||||
if !ok {
|
|
||||||
return zero, ErrorChannelBufferClose
|
|
||||||
}
|
|
||||||
// TODO: NIL CHECK IS REQUIRED BUT GENERIC CANNOT DO THIS. SOLVE THIS ASAP
|
|
||||||
// if data == nil {
|
|
||||||
// return zero, ErrorElementUnallocated
|
|
||||||
// }
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buffer *ChannelBuffer[T]) Generate() T {
|
|
||||||
return buffer.pool.Get()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buffer *ChannelBuffer[T]) PutBack(element T) {
|
|
||||||
if buffer.pool != nil {
|
|
||||||
buffer.pool.Put(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buffer *ChannelBuffer[T]) GetChannel() chan T {
|
|
||||||
return buffer.bufferChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buffer *ChannelBuffer[T]) Size() int {
|
|
||||||
return len(buffer.bufferChannel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buffer *ChannelBuffer[T]) loop() {
|
|
||||||
defer buffer.close()
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-buffer.ctx.Done():
|
|
||||||
return
|
|
||||||
case element, ok := <-buffer.inputBuffer:
|
|
||||||
// if !ok || element == nil {
|
|
||||||
// continue loop
|
|
||||||
// }
|
|
||||||
if !ok {
|
|
||||||
continue loop
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case buffer.bufferChannel <- element: // SUCCESSFULLY BUFFERED
|
|
||||||
continue loop
|
|
||||||
default:
|
|
||||||
select {
|
|
||||||
case oldElement := <-buffer.bufferChannel:
|
|
||||||
buffer.PutBack(oldElement)
|
|
||||||
select {
|
|
||||||
case buffer.bufferChannel <- element:
|
|
||||||
continue loop
|
|
||||||
default:
|
|
||||||
fmt.Println("unexpected buffer state. skipping the element..")
|
|
||||||
buffer.PutBack(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buffer *ChannelBuffer[T]) close() {
|
|
||||||
buffer.mux.Lock()
|
|
||||||
buffer.closed = true
|
|
||||||
buffer.mux.Unlock()
|
|
||||||
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case element := <-buffer.bufferChannel:
|
|
||||||
if buffer.pool != nil {
|
|
||||||
buffer.pool.Put(element)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
close(buffer.bufferChannel)
|
|
||||||
close(buffer.inputBuffer)
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if buffer.pool != nil {
|
|
||||||
buffer.pool.Release()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
24
dependencies/tools/pkg/buffer/package.go
vendored
24
dependencies/tools/pkg/buffer/package.go
vendored
@@ -1,24 +0,0 @@
|
|||||||
// TODO: CLEAN THIS; THIS IS STUPID
|
|
||||||
|
|
||||||
package buffer
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type Pool[T any] interface {
|
|
||||||
Get() T
|
|
||||||
Put(T)
|
|
||||||
Release()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Buffer[T any] interface {
|
|
||||||
Push(context.Context, T) error
|
|
||||||
Pop(ctx context.Context) (T, error)
|
|
||||||
Size() int
|
|
||||||
}
|
|
||||||
|
|
||||||
type BufferWithGenerator[T any] interface {
|
|
||||||
Buffer[T]
|
|
||||||
Generate() T
|
|
||||||
PutBack(T)
|
|
||||||
GetChannel() chan T
|
|
||||||
}
|
|
||||||
55
dependencies/tools/pkg/buffer/packet_pool.go
vendored
55
dependencies/tools/pkg/buffer/packet_pool.go
vendored
@@ -1,55 +0,0 @@
|
|||||||
//go:build cgo_enabled
|
|
||||||
|
|
||||||
package buffer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/asticode/go-astiav"
|
|
||||||
)
|
|
||||||
|
|
||||||
type packetPool struct {
|
|
||||||
pool sync.Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreatePacketPool() Pool[*astiav.Packet] {
|
|
||||||
return &packetPool{
|
|
||||||
pool: sync.Pool{
|
|
||||||
New: func() any {
|
|
||||||
return astiav.AllocPacket()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *packetPool) Get() *astiav.Packet {
|
|
||||||
packet, ok := pool.pool.Get().(*astiav.Packet)
|
|
||||||
|
|
||||||
if packet == nil || !ok {
|
|
||||||
return astiav.AllocPacket()
|
|
||||||
}
|
|
||||||
return packet
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *packetPool) Put(packet *astiav.Packet) {
|
|
||||||
if packet == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
packet.Unref()
|
|
||||||
pool.pool.Put(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pool *packetPool) Release() {
|
|
||||||
for {
|
|
||||||
packet, ok := pool.pool.Get().(*astiav.Packet)
|
|
||||||
if packet == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// fmt.Printf("🗑️ Releasing packet: ptr=%p\n", packet)
|
|
||||||
packet.Free()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
338
dependencies/tools/pkg/metrics/metrics.go
vendored
338
dependencies/tools/pkg/metrics/metrics.go
vendored
@@ -1,338 +0,0 @@
|
|||||||
package metrics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ClientState int
|
|
||||||
|
|
||||||
const (
|
|
||||||
ClientStateDisconnected ClientState = iota
|
|
||||||
ClientStateConnecting
|
|
||||||
ClientStateConnected
|
|
||||||
ClientStateError
|
|
||||||
)
|
|
||||||
|
|
||||||
func (cs ClientState) String() string {
|
|
||||||
switch cs {
|
|
||||||
case ClientStateDisconnected:
|
|
||||||
return "Disconnected"
|
|
||||||
case ClientStateConnecting:
|
|
||||||
return "Connecting"
|
|
||||||
case ClientStateConnected:
|
|
||||||
return "Connected"
|
|
||||||
case ClientStateError:
|
|
||||||
return "Error"
|
|
||||||
default:
|
|
||||||
return "Unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type BufferedErrors struct {
|
|
||||||
maxSize int
|
|
||||||
errors []ErrorEntry
|
|
||||||
mux sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrorEntry struct {
|
|
||||||
Timestamp time.Time `json:"timestamp"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBufferedErrors(maxSize int) *BufferedErrors {
|
|
||||||
return &BufferedErrors{
|
|
||||||
maxSize: maxSize,
|
|
||||||
errors: make([]ErrorEntry, 0, maxSize),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (be *BufferedErrors) Add(err error) {
|
|
||||||
be.mux.Lock()
|
|
||||||
defer be.mux.Unlock()
|
|
||||||
|
|
||||||
if len(be.errors) >= be.maxSize {
|
|
||||||
be.errors = be.errors[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
be.errors = append(be.errors, ErrorEntry{
|
|
||||||
Timestamp: time.Now(),
|
|
||||||
Message: err.Error(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (be *BufferedErrors) MarshalJSON() ([]byte, error) {
|
|
||||||
be.mux.RLock()
|
|
||||||
defer be.mux.RUnlock()
|
|
||||||
|
|
||||||
return json.Marshal(be.errors)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MetricsSnapshot struct {
|
|
||||||
State string `json:"state"`
|
|
||||||
PacketsRead uint64 `json:"packetsRead"`
|
|
||||||
PacketsWritten uint64 `json:"packetsWritten"`
|
|
||||||
BytesRead uint64 `json:"bytesRead"`
|
|
||||||
BytesWritten uint64 `json:"bytesWritten"`
|
|
||||||
BytesReadRate float32 `json:"bytesReadRate"`
|
|
||||||
BytesWrittenRate float32 `json:"bytesWrittenRate"`
|
|
||||||
LastWriteTime *time.Time `json:"lastWriteTime,omitempty"`
|
|
||||||
LastReadTime *time.Time `json:"lastReadTime,omitempty"`
|
|
||||||
RecentErrors *BufferedErrors `json:"recentErrors"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UnifiedMetrics struct {
|
|
||||||
// Basic state
|
|
||||||
state ClientState
|
|
||||||
packetsRead uint64
|
|
||||||
packetsWritten uint64
|
|
||||||
bytesRead uint64
|
|
||||||
bytesWritten uint64
|
|
||||||
lastWriteTime time.Time
|
|
||||||
lastReadTime time.Time
|
|
||||||
recentErrors *BufferedErrors
|
|
||||||
|
|
||||||
// Rate calculation
|
|
||||||
lastBytesRead uint64
|
|
||||||
lastBytesWritten uint64
|
|
||||||
bytesReadRate float32
|
|
||||||
bytesWrittenRate float32
|
|
||||||
tickerInterval time.Duration
|
|
||||||
|
|
||||||
// Control
|
|
||||||
serviceTitle string
|
|
||||||
ctx context.Context
|
|
||||||
cancel context.CancelFunc
|
|
||||||
wg sync.WaitGroup
|
|
||||||
mux sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUnifiedMetrics(ctx context.Context, serviceTitle string, maxErrorBuffer int, tickerInterval time.Duration) *UnifiedMetrics {
|
|
||||||
ctx2, cancel := context.WithCancel(ctx)
|
|
||||||
m := &UnifiedMetrics{
|
|
||||||
state: ClientStateDisconnected,
|
|
||||||
recentErrors: NewBufferedErrors(maxErrorBuffer),
|
|
||||||
serviceTitle: serviceTitle,
|
|
||||||
tickerInterval: tickerInterval,
|
|
||||||
ctx: ctx2,
|
|
||||||
cancel: cancel,
|
|
||||||
}
|
|
||||||
|
|
||||||
m.wg.Add(1)
|
|
||||||
go m.loop()
|
|
||||||
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) loop() {
|
|
||||||
defer m.wg.Done()
|
|
||||||
|
|
||||||
ticker := time.NewTicker(m.tickerInterval)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-m.ctx.Done():
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
m.updateRatesAndPrint()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) updateRatesAndPrint() {
|
|
||||||
m.mux.Lock()
|
|
||||||
|
|
||||||
currentBytesRead := m.bytesRead
|
|
||||||
currentBytesWritten := m.bytesWritten
|
|
||||||
|
|
||||||
intervalSeconds := float32(m.tickerInterval.Seconds())
|
|
||||||
m.bytesReadRate = float32(currentBytesRead-m.lastBytesRead) / intervalSeconds
|
|
||||||
m.bytesWrittenRate = float32(currentBytesWritten-m.lastBytesWritten) / intervalSeconds
|
|
||||||
|
|
||||||
m.lastBytesRead = currentBytesRead
|
|
||||||
m.lastBytesWritten = currentBytesWritten
|
|
||||||
|
|
||||||
m.mux.Unlock()
|
|
||||||
|
|
||||||
snapshot := m.GetSnapshot()
|
|
||||||
|
|
||||||
m.printFormattedMetrics(snapshot)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) printFormattedMetrics(snapshot MetricsSnapshot) {
|
|
||||||
divider := "================================================"
|
|
||||||
|
|
||||||
fmt.Printf("\n%s\n", divider)
|
|
||||||
fmt.Printf("%*s\n", (len(divider)+len(m.serviceTitle))/2, m.serviceTitle)
|
|
||||||
fmt.Printf("%s\n\n", divider)
|
|
||||||
|
|
||||||
fmt.Printf("%-20s: %s\n", "Connection State", snapshot.State)
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
fmt.Printf("%-20s: %d\n", "Packets Read", snapshot.PacketsRead)
|
|
||||||
fmt.Printf("%-20s: %d\n", "Packets Written", snapshot.PacketsWritten)
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
fmt.Printf("%-20s: %s\n", "Bytes Read", formatBytes(snapshot.BytesRead))
|
|
||||||
fmt.Printf("%-20s: %s\n", "Bytes Written", formatBytes(snapshot.BytesWritten))
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
fmt.Printf("%-20s: %s/s\n", "Read Rate", formatBytes(uint64(snapshot.BytesReadRate)))
|
|
||||||
fmt.Printf("%-20s: %s/s\n", "Write Rate", formatBytes(uint64(snapshot.BytesWrittenRate)))
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
if snapshot.LastReadTime != nil {
|
|
||||||
fmt.Printf("%-20s: %s\n", "Last Read", snapshot.LastReadTime.Format("2006-01-02 15:04:05"))
|
|
||||||
}
|
|
||||||
if snapshot.LastWriteTime != nil {
|
|
||||||
fmt.Printf("%-20s: %s\n", "Last Write", snapshot.LastWriteTime.Format("2006-01-02 15:04:05"))
|
|
||||||
}
|
|
||||||
if snapshot.LastReadTime != nil || snapshot.LastWriteTime != nil {
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
snapshot.RecentErrors.mux.RLock()
|
|
||||||
errorCount := len(snapshot.RecentErrors.errors)
|
|
||||||
if errorCount > 0 {
|
|
||||||
fmt.Printf("Recent Errors (%d error", errorCount)
|
|
||||||
if errorCount != 1 {
|
|
||||||
fmt.Print("s")
|
|
||||||
}
|
|
||||||
fmt.Println("):")
|
|
||||||
|
|
||||||
for _, errorEntry := range snapshot.RecentErrors.errors {
|
|
||||||
fmt.Printf(" [%s] %s\n",
|
|
||||||
errorEntry.Timestamp.Format("15:04:05"),
|
|
||||||
errorEntry.Message)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
snapshot.RecentErrors.mux.RUnlock()
|
|
||||||
|
|
||||||
fmt.Printf("%s\n", divider)
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatBytes(bytes uint64) string {
|
|
||||||
if bytes < 1024 {
|
|
||||||
return fmt.Sprintf("%d B", bytes)
|
|
||||||
} else if bytes < 1024*1024 {
|
|
||||||
return fmt.Sprintf("%.2f KB", float64(bytes)/1024)
|
|
||||||
} else if bytes < 1024*1024*1024 {
|
|
||||||
return fmt.Sprintf("%.2f MB", float64(bytes)/(1024*1024))
|
|
||||||
} else {
|
|
||||||
return fmt.Sprintf("%.2f GB", float64(bytes)/(1024*1024*1024))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) Close() error {
|
|
||||||
if m.cancel != nil {
|
|
||||||
m.cancel()
|
|
||||||
m.wg.Wait()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) SetState(state ClientState) {
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
m.state = state
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) GetState() ClientState {
|
|
||||||
m.mux.RLock()
|
|
||||||
defer m.mux.RUnlock()
|
|
||||||
return m.state
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) IncrementPacketsWritten() {
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
m.packetsWritten++
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) IncrementPacketsRead() {
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
m.packetsRead++
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) IncrementBytesWritten(bytes uint64) {
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
m.bytesWritten += bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) IncrementBytesRead(bytes uint64) {
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
m.bytesRead += bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) SetLastWriteTime(t time.Time) {
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
m.lastWriteTime = t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) SetLastReadTime(t time.Time) {
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
m.lastReadTime = t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) GetLastWriteTime() time.Time {
|
|
||||||
m.mux.RLock()
|
|
||||||
defer m.mux.RUnlock()
|
|
||||||
return m.lastWriteTime
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) GetLastReadTime() time.Time {
|
|
||||||
m.mux.RLock()
|
|
||||||
defer m.mux.RUnlock()
|
|
||||||
return m.lastReadTime
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) AddErrors(errs ...error) {
|
|
||||||
if len(errs) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
m.mux.Lock()
|
|
||||||
defer m.mux.Unlock()
|
|
||||||
|
|
||||||
for _, err := range errs {
|
|
||||||
if err == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
m.recentErrors.Add(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *UnifiedMetrics) GetSnapshot() MetricsSnapshot {
|
|
||||||
m.mux.RLock()
|
|
||||||
defer m.mux.RUnlock()
|
|
||||||
|
|
||||||
snapshot := MetricsSnapshot{
|
|
||||||
State: m.state.String(),
|
|
||||||
PacketsRead: m.packetsRead,
|
|
||||||
PacketsWritten: m.packetsWritten,
|
|
||||||
BytesRead: m.bytesRead,
|
|
||||||
BytesWritten: m.bytesWritten,
|
|
||||||
BytesReadRate: m.bytesReadRate,
|
|
||||||
BytesWrittenRate: m.bytesWrittenRate,
|
|
||||||
RecentErrors: m.recentErrors,
|
|
||||||
}
|
|
||||||
|
|
||||||
if !m.lastReadTime.IsZero() {
|
|
||||||
snapshot.LastReadTime = &m.lastReadTime
|
|
||||||
}
|
|
||||||
if !m.lastWriteTime.IsZero() {
|
|
||||||
snapshot.LastWriteTime = &m.lastWriteTime
|
|
||||||
}
|
|
||||||
|
|
||||||
return snapshot
|
|
||||||
}
|
|
||||||
116
dependencies/tools/pkg/multierr/multierr.go
vendored
116
dependencies/tools/pkg/multierr/multierr.go
vendored
@@ -1,116 +0,0 @@
|
|||||||
// Package multierr provides utilities for combining multiple errors into a single error.
|
|
||||||
package multierr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Combine takes a list of errors and combines them into a single error.
|
|
||||||
// If all errors are nil, it returns nil.
|
|
||||||
// If there's only one non-nil error, it returns that error.
|
|
||||||
// If there are multiple non-nil errors, it combines them into a single error.
|
|
||||||
func Combine(errs ...error) error {
|
|
||||||
var nonNilErrs []error
|
|
||||||
for _, err := range errs {
|
|
||||||
if err != nil {
|
|
||||||
nonNilErrs = append(nonNilErrs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(nonNilErrs) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(nonNilErrs) == 1 {
|
|
||||||
return nonNilErrs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return &multiError{
|
|
||||||
errors: nonNilErrs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append combines the two errors into a single error.
|
|
||||||
// If both errors are nil, it returns nil.
|
|
||||||
// If one error is nil, it returns the non-nil error.
|
|
||||||
// If both errors are non-nil, it combines them into a single error.
|
|
||||||
func Append(err1, err2 error) error {
|
|
||||||
if err1 == nil {
|
|
||||||
return err2
|
|
||||||
}
|
|
||||||
|
|
||||||
if err2 == nil {
|
|
||||||
return err1
|
|
||||||
}
|
|
||||||
|
|
||||||
// If err1 is already a multiError, append err2 to it
|
|
||||||
if me, ok := err1.(*multiError); ok {
|
|
||||||
return &multiError{
|
|
||||||
errors: append(me.errors, err2),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If err2 is already a multiError, prepend err1 to it
|
|
||||||
if me, ok := err2.(*multiError); ok {
|
|
||||||
return &multiError{
|
|
||||||
errors: append([]error{err1}, me.errors...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Neither error is a multiError, create a new one
|
|
||||||
return &multiError{
|
|
||||||
errors: []error{err1, err2},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiError is an implementation of error that contains multiple errors.
|
|
||||||
type multiError struct {
|
|
||||||
errors []error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error returns a string representation of all the errors.
|
|
||||||
func (m *multiError) Error() string {
|
|
||||||
if len(m.errors) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(m.errors) == 1 {
|
|
||||||
return m.errors[0].Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
var sb strings.Builder
|
|
||||||
sb.WriteString(fmt.Sprintf("%d errors occurred:\n", len(m.errors)))
|
|
||||||
for i, err := range m.errors {
|
|
||||||
sb.WriteString(fmt.Sprintf(" %d: %s\n", i+1, err.Error()))
|
|
||||||
}
|
|
||||||
return sb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap returns the underlying errors.
|
|
||||||
// This allows errors.Is and errors.As to work with multiError.
|
|
||||||
func (m *multiError) Unwrap() []error {
|
|
||||||
return m.errors
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is reports whether any error in multiError matches target.
|
|
||||||
func (m *multiError) Is(target error) bool {
|
|
||||||
for _, err := range m.errors {
|
|
||||||
if errors.Is(err, target) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// As finds the first error in multiError that matches target, and if one is found, sets
|
|
||||||
// target to that error value and returns true. Otherwise, it returns false.
|
|
||||||
func (m *multiError) As(target interface{}) bool {
|
|
||||||
for _, err := range m.errors {
|
|
||||||
if errors.As(err, target) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user