|
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"hash"
|
|
"io"
|
|
"math"
|
|
"net/url"
|
|
"reflect"
|
|
"sort"
|
|
"sync/atomic"
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
MaxRetries = 3
|
|
BaseDelay = 100 * time.Millisecond
|
|
MaxDelay = 5 * time.Second
|
|
)
|
|
|
|
type Executor[T any] struct {
|
|
workers int
|
|
tasks chan func() T
|
|
results chan T
|
|
}
|
|
|
|
func NewExecutor[T any](workers int) *Executor[T] {
|
|
return &Executor[T]{
|
|
workers: workers,
|
|
tasks: make(chan func() T, workers*2),
|
|
results: make(chan T, workers*2),
|
|
}
|
|
}
|
|
|
|
func (e *Executor[T]) Submit(task func() T) {
|
|
e.tasks <- task
|
|
}
|
|
|
|
func (e *Executor[T]) Run(ctx context.Context) []T {
|
|
for i := 0; i < e.workers; i++ {
|
|
go func() {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case task := <-e.tasks:
|
|
e.results <- task()
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
var results []T
|
|
for i := 0; i < cap(e.tasks); i++ {
|
|
select {
|
|
case r := <-e.results:
|
|
results = append(results, r)
|
|
case <-ctx.Done():
|
|
return results
|
|
}
|
|
}
|
|
return results
|
|
}
|
|
|
|
func retryWithBackoff(operation func() error) error {
|
|
var err error
|
|
delay := BaseDelay
|
|
|
|
for i := 0; i < MaxRetries; i++ {
|
|
if err = operation(); err == nil {
|
|
return nil
|
|
}
|
|
if i < MaxRetries-1 {
|
|
jitter := time.Duration(rand.Int63n(int64(delay / 2)))
|
|
time.Sleep(delay + jitter)
|
|
delay = time.Duration(math.Min(float64(delay*2), float64(MaxDelay)))
|
|
}
|
|
}
|
|
return fmt.Errorf("operation failed after %d retries: %w", MaxRetries, err)
|
|
}
|
|
|
|
func HashContent(r io.Reader) (string, error) {
|
|
h := sha256.New()
|
|
if _, err := io.Copy(h, r); err != nil {
|
|
return "", fmt.Errorf("hashing failed: %w", err)
|
|
}
|
|
return hex.EncodeToString(h.Sum(nil)), nil
|
|
}
|
|
|
|
func SliceToMap[K comparable, V any](items []V, keyFn func(V) K) map[K]V {
|
|
result := make(map[K]V, len(items))
|
|
for _, item := range items {
|
|
result[keyFn(item)] = item
|
|
}
|
|
return result
|
|
}
|
|
|
|
func InverseMap[K, V comparable](m map[K]V) map[V]K {
|
|
result := make(map[V]K, len(m))
|
|
for k, v := range m {
|
|
result[v] = k
|
|
}
|
|
return result
|
|
}
|
|
|
|
var counter atomic.Int64
|
|
|
|
func nextID() int64 {
|
|
return counter.Add(1)
|
|
}
|
|
|
|
type Enum interface {
|
|
~int
|
|
String() string
|
|
}
|
|
|
|
type Color int
|
|
|
|
const (
|
|
Red Color = iota
|
|
Green
|
|
Blue
|
|
)
|
|
|
|
func (c Color) String() string {
|
|
return [...]string{"red", "green", "blue"}[c]
|
|
}
|
|
|
|
func Must[T any](val T, err error) T {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return val
|
|
}
|
|
|
|
type TransformFunc[T, U any] func(T) U
|
|
|
|
func Chain[T, U, V any](f TransformFunc[T, U], g TransformFunc[U, V]) TransformFunc[T, V] {
|
|
return func(t T) V {
|
|
return g(f(t))
|
|
}
|
|
}
|
|
|
|
func zero[T any]() T {
|
|
var zero T
|
|
return zero
|
|
}
|
|
|
|
func Map[T, U any](items []T, fn func(T) U) []U {
|
|
result := make([]U, len(items))
|
|
for i, item := range items {
|
|
result[i] = fn(item)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func Filter[T any](items []T, fn func(T) bool) []T {
|
|
var result []T
|
|
for _, item := range items {
|
|
if fn(item) {
|
|
result = append(result, item)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func Reduce[T, U any](items []T, init U, fn func(U, T) U) U {
|
|
acc := init
|
|
for _, item := range items {
|
|
acc = fn(acc, item)
|
|
}
|
|
return acc
|
|
}
|
|
|
|
func init() {
|
|
fmt.Println("initializing package main")
|
|
}
|