docs(ax): improve proxy API comments

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-05 00:25:30 +00:00
parent 9460f82738
commit 2364633afc
7 changed files with 83 additions and 39 deletions

View file

@ -1,6 +1,9 @@
package proxy
// LoadConfig("/etc/proxy.json")
// Config is the top-level proxy configuration.
//
// cfg, result := proxy.LoadConfig("/etc/proxy.json")
// if !result.OK { return result.Error }
type Config struct {
Mode string `json:"mode"` // "nicehash" or "simple"
Bind []BindAddr `json:"bind"` // listen addresses
@ -22,14 +25,18 @@ type Config struct {
configPath string
}
// BindAddr{Host: "0.0.0.0", Port: 3333, TLS: false}
// BindAddr is one TCP listen endpoint.
//
// proxy.BindAddr{Host: "0.0.0.0", Port: 3333, TLS: false}
type BindAddr struct {
Host string `json:"host"`
Port uint16 `json:"port"`
TLS bool `json:"tls"`
}
// PoolConfig{URL: "pool.lthn.io:3333", User: "WALLET", Pass: "x", Enabled: true}
// PoolConfig is one upstream pool entry.
//
// proxy.PoolConfig{URL: "pool.lthn.io:3333", User: "WALLET", Pass: "x", Enabled: true}
type PoolConfig struct {
URL string `json:"url"`
User string `json:"user"`
@ -42,7 +49,9 @@ type PoolConfig struct {
Enabled bool `json:"enabled"`
}
// TLSConfig{Enabled: true, CertFile: "/etc/proxy/cert.pem", KeyFile: "/etc/proxy/key.pem"}
// TLSConfig controls inbound TLS for miner listeners.
//
// proxy.TLSConfig{Enabled: true, CertFile: "/etc/proxy/cert.pem", KeyFile: "/etc/proxy/key.pem"}
type TLSConfig struct {
Enabled bool `json:"enabled"`
CertFile string `json:"cert"`
@ -51,7 +60,9 @@ type TLSConfig struct {
Protocols string `json:"protocols"` // TLS version string; "" = default
}
// HTTPConfig{Enabled: true, Host: "127.0.0.1", Port: 8080, Restricted: true}
// HTTPConfig controls the monitoring API server.
//
// proxy.HTTPConfig{Enabled: true, Host: "127.0.0.1", Port: 8080, Restricted: true}
type HTTPConfig struct {
Enabled bool `json:"enabled"`
Host string `json:"host"`
@ -60,13 +71,17 @@ type HTTPConfig struct {
Restricted bool `json:"restricted"` // true = read-only GET only
}
// RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300}
// RateLimit controls per-IP connection throttling.
//
// proxy.RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300}
type RateLimit struct {
MaxConnectionsPerMinute int `json:"max-connections-per-minute"` // 0 = disabled
BanDurationSeconds int `json:"ban-duration"` // 0 = no ban
}
// WorkersByRigID
// WorkersMode selects the login field used as the worker identity.
//
// proxy.WorkersByRigID
type WorkersMode string
const (

View file

@ -2,15 +2,19 @@ package proxy
import "sync"
// EventBus dispatches proxy lifecycle events to synchronous listeners.
//
// bus := proxy.NewEventBus()
// bus.Subscribe(proxy.EventLogin, func(e proxy.Event) { fmt.Println(e.Miner.User()) })
// bus.Subscribe(proxy.EventLogin, func(e proxy.Event) { _ = e.Miner.User() })
// bus.Subscribe(proxy.EventAccept, stats.OnAccept)
type EventBus struct {
listeners map[EventType][]EventHandler
mu sync.RWMutex
}
// EventType identifies the proxy lifecycle event.
// EventType identifies one proxy lifecycle event.
//
// proxy.EventLogin
type EventType int
const (
@ -21,12 +25,13 @@ const (
)
// EventHandler is the callback signature for all event types.
//
// handler := func(e proxy.Event) { _ = e.Miner }
type EventHandler func(Event)
// Event carries the data for any proxy lifecycle event.
// Fields not relevant to the event type are zero/nil.
//
// bus.Dispatch(proxy.Event{Type: proxy.EventLogin, Miner: m})
// bus.Dispatch(proxy.Event{Type: proxy.EventLogin, Miner: m})
type Event struct {
Type EventType
Miner *Miner // always set

9
job.go
View file

@ -1,13 +1,8 @@
package proxy
// Job holds the current work unit received from a pool. Immutable once assigned.
// Job holds one pool work unit and its metadata.
//
// j := proxy.Job{
// Blob: "0707d5ef...b01",
// JobID: "4BiGm3/RgGQzgkTI",
// Target: "b88d0600",
// Algo: "cn/r",
// }
// j := proxy.Job{Blob: "0707d5ef...b01", JobID: "4BiGm3/RgGQzgkTI", Target: "b88d0600", Algo: "cn/r"}
type Job struct {
Blob string // hex-encoded block template (160 hex chars = 80 bytes)
JobID string // pool-assigned identifier

View file

@ -17,11 +17,10 @@ import (
"time"
)
// p, result := proxy.New(cfg)
// Proxy owns the servers, splitters, stats, workers, and monitoring API.
//
// if result.OK {
// p.Start()
// }
// p, result := proxy.New(cfg)
// if result.OK { p.Start() }
type Proxy struct {
config *Config
splitter Splitter
@ -44,6 +43,8 @@ type Proxy struct {
submitCount atomic.Int64
}
// Splitter is the shared interface implemented by the NiceHash and simple modes.
//
// type stubSplitter struct{}
//
// func (stubSplitter) Connect() {}
@ -64,7 +65,9 @@ type Splitter interface {
Upstreams() UpstreamStats
}
// UpstreamStats{Active: 1, Sleep: 0, Error: 0, Total: 1}
// UpstreamStats reports pool connection counts.
//
// stats := proxy.UpstreamStats{Active: 1, Sleep: 0, Error: 0, Total: 1}
type UpstreamStats struct {
Active uint64 // connections currently receiving jobs
Sleep uint64 // idle connections (simple mode reuse pool)
@ -72,12 +75,16 @@ type UpstreamStats struct {
Total uint64 // Active + Sleep + Error
}
// LoginEvent{Miner: miner}
// LoginEvent is dispatched when a miner completes login.
//
// event := proxy.LoginEvent{Miner: miner}
type LoginEvent struct {
Miner *Miner
}
// SubmitEvent{Miner: miner, JobID: "job-1", Nonce: "deadbeef", Result: "HASH", RequestID: 2}
// SubmitEvent carries one miner share submission.
//
// event := proxy.SubmitEvent{Miner: miner, JobID: "job-1", Nonce: "deadbeef", Result: "HASH", RequestID: 2}
type SubmitEvent struct {
Miner *Miner
JobID string
@ -87,12 +94,16 @@ type SubmitEvent struct {
RequestID int64
}
// CloseEvent{Miner: miner}
// CloseEvent is dispatched when a miner connection closes.
//
// event := proxy.CloseEvent{Miner: miner}
type CloseEvent struct {
Miner *Miner
}
// NewConfigWatcher("config.json", func(cfg *Config) { p.Reload(cfg) })
// ConfigWatcher polls a config file for changes.
//
// watcher := proxy.NewConfigWatcher("config.json", func(cfg *proxy.Config) { p.Reload(cfg) })
type ConfigWatcher struct {
path string
onChange func(*Config)
@ -100,7 +111,9 @@ type ConfigWatcher struct {
done chan struct{}
}
// limiter := NewRateLimiter(RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300})
// RateLimiter throttles new connections per source IP.
//
// limiter := proxy.NewRateLimiter(proxy.RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300})
// limiter.Allow("1.2.3.4:3333")
type RateLimiter struct {
config RateLimit
@ -109,13 +122,17 @@ type RateLimiter struct {
mu sync.Mutex
}
// tokenBucket{tokens: 30, lastRefill: time.Now()}
// tokenBucket is the per-IP refillable counter.
//
// bucket := tokenBucket{tokens: 30, lastRefill: time.Now()}
type tokenBucket struct {
tokens int
lastRefill time.Time
}
// resolver := NewCustomDiff(50000)
// CustomDiff applies a login-time difficulty override.
//
// resolver := proxy.NewCustomDiff(50000)
// resolver.Apply(&Miner{user: "WALLET+75000"})
type CustomDiff struct {
globalDiff uint64

View file

@ -7,8 +7,8 @@ import (
// Server listens on one BindAddr and creates a Miner for each accepted connection.
//
// srv, result := proxy.NewServer(bind, tlsCfg, rateLimiter, onAccept)
// srv.Start()
// srv, result := proxy.NewServer(bind, tlsCfg, rateLimiter, onAccept)
// if result.OK { srv.Start() }
type Server struct {
addr BindAddr
tlsCfg *tls.Config // nil for plain TCP

View file

@ -6,9 +6,11 @@ import (
"time"
)
// stats := NewStats()
// bus.Subscribe(EventAccept, stats.OnAccept)
// bus.Subscribe(EventReject, stats.OnReject)
// Stats tracks the proxy-wide counters and rolling hashrate windows.
//
// stats := proxy.NewStats()
// bus.Subscribe(proxy.EventAccept, stats.OnAccept)
// bus.Subscribe(proxy.EventReject, stats.OnReject)
type Stats struct {
accepted atomic.Uint64
rejected atomic.Uint64
@ -25,7 +27,9 @@ type Stats struct {
mu sync.Mutex
}
// HashrateWindow60s
// HashrateWindow60s selects the 60-second hashrate window.
//
// proxy.HashrateWindow60s
const (
HashrateWindow60s = 0 // 1 minute
HashrateWindow600s = 1 // 10 minutes
@ -35,14 +39,18 @@ const (
HashrateWindowAll = 5 // all-time (single accumulator, no window)
)
// newTickWindow(60)
// tickWindow is a fixed-capacity ring buffer of per-second difficulty totals.
//
// window := newTickWindow(60)
type tickWindow struct {
buckets []uint64
pos int
size int // window size in seconds = len(buckets)
}
// NewStats().Summary()
// StatsSummary is the serialisable snapshot returned by Stats.Summary().
//
// summary := proxy.NewStats().Summary()
type StatsSummary struct {
Accepted uint64 `json:"accepted"`
Rejected uint64 `json:"rejected"`

View file

@ -5,7 +5,9 @@ import (
"time"
)
// workers := NewWorkers(WorkersByRigID, bus)
// Workers tracks per-identity aggregates derived from miner login fields.
//
// workers := proxy.NewWorkers(proxy.WorkersByRigID, bus)
// records := workers.List()
type Workers struct {
mode WorkersMode
@ -16,6 +18,8 @@ type Workers struct {
mu sync.RWMutex
}
// WorkerRecord is the aggregate row returned by Workers.List().
//
// record.Hashrate(60)
type WorkerRecord struct {
Name string