Re-add tools submodule properly

This commit is contained in:
harshabose
2025-07-12 18:18:45 +05:30
parent e42f61ba5e
commit ae10e7491f
11 changed files with 1 additions and 809 deletions

1
dependencies/tools vendored Submodule

Submodule dependencies/tools added at d5ed322260

View File

@@ -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/

View File

@@ -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

View File

@@ -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=

View File

@@ -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")
)

View File

@@ -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()
}
}

View File

@@ -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()
}
}

View File

@@ -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
}

View File

@@ -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()
}
}

View File

@@ -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
}

View File

@@ -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
}