docs(proxy): align API comments with AX

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-04 23:48:33 +00:00
parent 9e44fb6ea3
commit fd6bc01b87
7 changed files with 50 additions and 103 deletions

View file

@ -16,16 +16,13 @@ import (
"dappco.re/go/proxy"
)
// Router matches the standard http.ServeMux registration shape.
// http.NewServeMux()
type Router interface {
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
}
// RegisterRoutes wires the monitoring endpoints onto the supplied router.
//
// mux := http.NewServeMux()
// proxyapi.RegisterRoutes(mux, p)
// // GET /1/summary, /1/workers, and /1/miners are now live.
// mux := http.NewServeMux()
// RegisterRoutes(mux, p)
func RegisterRoutes(router Router, p *proxy.Proxy) {
if router == nil || p == nil {
return

View file

@ -1,18 +1,12 @@
package proxy
// WorkerRow is one row in the /1/workers table.
//
// WorkerRow{"rig-alpha", "10.0.0.1", 1, 10, 0, 0, 100000, 1712232000, 1.0, 1.0, 1.0, 1.0, 1.0}
// WorkerRow{"rig-alpha", "10.0.0.1", 1, 10, 0, 0, 100000, 1712232000, 1.0, 1.0, 1.0, 1.0, 1.0}
type WorkerRow [13]any
// MinerRow is one row in the /1/miners table.
//
// MinerRow{1, "10.0.0.1:49152", 4096, 512, 2, 100000, "WALLET", "********", "rig-alpha", "XMRig/6.21.0"}
// MinerRow{1, "10.0.0.1:49152", 4096, 512, 2, 100000, "WALLET", "********", "rig-alpha", "XMRig/6.21.0"}
type MinerRow [10]any
// SummaryDocument is the RFC-shaped /1/summary response body.
//
// doc := p.SummaryDocument()
// p.SummaryDocument()
type SummaryDocument struct {
Version string `json:"version"`
Mode string `json:"mode"`
@ -24,24 +18,18 @@ type SummaryDocument struct {
CustomDiffStats map[uint64]CustomDiffBucketStats `json:"custom_diff_stats,omitempty"`
}
// HashrateDocument carries the per-window hashrate array.
//
// HashrateDocument{Total: [6]float64{12345.67, 11900.00, 12100.00, 11800.00, 12000.00, 12200.00}}
// HashrateDocument{Total: [6]float64{12345.67, 11900.00, 12100.00, 11800.00, 12000.00, 12200.00}}
type HashrateDocument struct {
Total [6]float64 `json:"total"`
}
// MinersCountDocument carries current and peak miner counts.
//
// MinersCountDocument{Now: 142, Max: 200}
// MinersCountDocument{Now: 142, Max: 200}
type MinersCountDocument struct {
Now uint64 `json:"now"`
Max uint64 `json:"max"`
}
// UpstreamDocument carries pool connection state counts.
//
// UpstreamDocument{Active: 1, Sleep: 0, Error: 0, Total: 1, Ratio: 142.0}
// UpstreamDocument{Active: 1, Sleep: 0, Error: 0, Total: 1, Ratio: 142.0}
type UpstreamDocument struct {
Active uint64 `json:"active"`
Sleep uint64 `json:"sleep"`
@ -50,9 +38,7 @@ type UpstreamDocument struct {
Ratio float64 `json:"ratio"`
}
// ResultsDocument carries share acceptance statistics.
//
// ResultsDocument{Accepted: 4821, Rejected: 3, Invalid: 0, Expired: 12}
// ResultsDocument{Accepted: 4821, Rejected: 3, Invalid: 0, Expired: 12}
type ResultsDocument struct {
Accepted uint64 `json:"accepted"`
Rejected uint64 `json:"rejected"`
@ -64,17 +50,13 @@ type ResultsDocument struct {
Best [10]uint64 `json:"best"`
}
// WorkersDocument is the RFC-shaped /1/workers response body.
//
// doc := p.WorkersDocument()
// p.WorkersDocument()
type WorkersDocument struct {
Mode string `json:"mode"`
Workers []WorkerRow `json:"workers"`
}
// MinersDocument is the RFC-shaped /1/miners response body.
//
// doc := p.MinersDocument()
// p.MinersDocument()
type MinersDocument struct {
Format []string `json:"format"`
Miners []MinerRow `json:"miners"`

View file

@ -1,11 +1,6 @@
package proxy
// Config is the top-level proxy configuration, loaded from JSON and hot-reloaded on change.
//
// cfg, result := proxy.LoadConfig("/etc/proxy.json")
// if !result.OK {
// return result.Error
// }
// LoadConfig("/etc/proxy.json")
type Config struct {
Mode string `json:"mode"` // "nicehash" or "simple"
Bind []BindAddr `json:"bind"` // listen addresses
@ -27,18 +22,14 @@ type Config struct {
configPath string
}
// BindAddr is one TCP listen endpoint.
//
// proxy.BindAddr{Host: "0.0.0.0", Port: 3333, TLS: false}
// 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 is one upstream pool entry.
//
// proxy.PoolConfig{URL: "pool.lthn.io:3333", User: "WALLET", Pass: "x", Enabled: true}
// PoolConfig{URL: "pool.lthn.io:3333", User: "WALLET", Pass: "x", Enabled: true}
type PoolConfig struct {
URL string `json:"url"`
User string `json:"user"`
@ -51,9 +42,7 @@ type PoolConfig struct {
Enabled bool `json:"enabled"`
}
// TLSConfig controls inbound TLS on bind addresses that have TLS: true.
//
// proxy.TLSConfig{Enabled: true, CertFile: "/etc/proxy/cert.pem", KeyFile: "/etc/proxy/key.pem"}
// TLSConfig{Enabled: true, CertFile: "/etc/proxy/cert.pem", KeyFile: "/etc/proxy/key.pem"}
type TLSConfig struct {
Enabled bool `json:"enabled"`
CertFile string `json:"cert"`
@ -62,9 +51,7 @@ type TLSConfig struct {
Protocols string `json:"protocols"` // TLS version string; "" = default
}
// HTTPConfig controls the monitoring API server.
//
// proxy.HTTPConfig{Enabled: true, Host: "127.0.0.1", Port: 8080, Restricted: true}
// HTTPConfig{Enabled: true, Host: "127.0.0.1", Port: 8080, Restricted: true}
type HTTPConfig struct {
Enabled bool `json:"enabled"`
Host string `json:"host"`
@ -73,15 +60,13 @@ type HTTPConfig struct {
Restricted bool `json:"restricted"` // true = read-only GET only
}
// RateLimit controls per-IP connection rate limiting using a token bucket.
//
// proxy.RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300}
// 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
}
// WorkersMode controls which login field becomes the worker name.
// WorkersByRigID
type WorkersMode string
const (

View file

@ -12,12 +12,8 @@ import (
"dappco.re/go/proxy"
)
// StratumClient is one outbound stratum TCP (optionally TLS) connection to a pool.
// The proxy presents itself to the pool as a standard stratum miner using the
// wallet address and password from PoolConfig.
//
// client := pool.NewStratumClient(poolCfg, listener)
// client.Connect()
// client := NewStratumClient(poolCfg, listener)
// client.Connect()
type StratumClient struct {
config proxy.PoolConfig
listener StratumListener
@ -32,7 +28,9 @@ type StratumClient struct {
sendMu sync.Mutex
}
// StratumListener receives events from the pool connection.
// type listener struct{}
//
// func (listener) OnJob(job proxy.Job) {}
type StratumListener interface {
// OnJob is called when the pool pushes a new job notification or the login reply contains a job.
OnJob(job proxy.Job)

View file

@ -17,11 +17,11 @@ import (
"time"
)
// Proxy is the top-level orchestrator. It owns the server, splitter, stats, workers,
// event bus, tick goroutine, and optional HTTP API.
// p, result := proxy.New(cfg)
//
// p, result := proxy.New(cfg)
// if result.OK { p.Start() }
// if result.OK {
// p.Start()
// }
type Proxy struct {
config *Config
splitter Splitter
@ -44,7 +44,9 @@ type Proxy struct {
submitCount atomic.Int64
}
// Splitter is the interface both NonceSplitter and SimpleSplitter satisfy.
// type stubSplitter struct{}
//
// func (stubSplitter) Connect() {}
type Splitter interface {
// Connect establishes the first pool upstream connection.
Connect()
@ -62,7 +64,7 @@ type Splitter interface {
Upstreams() UpstreamStats
}
// UpstreamStats carries pool connection state counts for monitoring.
// 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)
@ -70,12 +72,12 @@ type UpstreamStats struct {
Total uint64 // Active + Sleep + Error
}
// LoginEvent is dispatched when a miner completes the login handshake.
// LoginEvent{Miner: miner}
type LoginEvent struct {
Miner *Miner
}
// SubmitEvent is dispatched when a miner submits a share.
// SubmitEvent{Miner: miner, JobID: "job-1", Nonce: "deadbeef", Result: "HASH", RequestID: 2}
type SubmitEvent struct {
Miner *Miner
JobID string
@ -85,15 +87,12 @@ type SubmitEvent struct {
RequestID int64
}
// CloseEvent is dispatched when a miner TCP connection closes.
// CloseEvent{Miner: miner}
type CloseEvent struct {
Miner *Miner
}
// ConfigWatcher polls a config file for mtime changes and calls onChange on modification.
//
// w := proxy.NewConfigWatcher("config.json", func(cfg *proxy.Config) { p.Reload(cfg) })
// w.Start()
// NewConfigWatcher("config.json", func(cfg *Config) { p.Reload(cfg) })
type ConfigWatcher struct {
path string
onChange func(*Config)
@ -101,10 +100,8 @@ type ConfigWatcher struct {
done chan struct{}
}
// RateLimiter implements per-IP token bucket connection rate limiting.
//
// rl := proxy.NewRateLimiter(proxy.RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300})
// if rl.Allow("1.2.3.4:3333") { proceed() }
// limiter := NewRateLimiter(RateLimit{MaxConnectionsPerMinute: 30, BanDurationSeconds: 300})
// limiter.Allow("1.2.3.4:3333")
type RateLimiter struct {
config RateLimit
buckets map[string]*tokenBucket
@ -112,17 +109,14 @@ type RateLimiter struct {
mu sync.Mutex
}
// tokenBucket is a simple token bucket for one IP.
// tokenBucket{tokens: 30, lastRefill: time.Now()}
type tokenBucket struct {
tokens int
lastRefill time.Time
}
// CustomDiff resolves and applies per-miner difficulty overrides at login time.
// Resolution order: user-suffix (+N) > Config.CustomDiff > pool difficulty.
//
// cd := proxy.NewCustomDiff(cfg.CustomDiff)
// bus.Subscribe(proxy.EventLogin, cd.OnLogin)
// resolver := NewCustomDiff(50000)
// resolver.Apply(&Miner{user: "WALLET+75000"})
type CustomDiff struct {
globalDiff uint64
}

View file

@ -6,12 +6,9 @@ import (
"time"
)
// Stats tracks global proxy metrics. Hot-path counters are atomic. Hashrate windows
// use a ring buffer per window size, advanced by Tick().
//
// stats := proxy.NewStats()
// bus.Subscribe(proxy.EventAccept, stats.OnAccept)
// bus.Subscribe(proxy.EventReject, stats.OnReject)
// stats := NewStats()
// bus.Subscribe(EventAccept, stats.OnAccept)
// bus.Subscribe(EventReject, stats.OnReject)
type Stats struct {
accepted atomic.Uint64
rejected atomic.Uint64
@ -28,7 +25,7 @@ type Stats struct {
mu sync.Mutex
}
// Hashrate window sizes in seconds. Index maps to Stats.windows and SummaryResponse.Hashrate.
// HashrateWindow60s
const (
HashrateWindow60s = 0 // 1 minute
HashrateWindow600s = 1 // 10 minutes
@ -38,16 +35,14 @@ const (
HashrateWindowAll = 5 // all-time (single accumulator, no window)
)
// tickWindow is a fixed-capacity ring buffer of per-second difficulty sums.
// newTickWindow(60)
type tickWindow struct {
buckets []uint64
pos int
size int // window size in seconds = len(buckets)
}
// StatsSummary is the serialisable snapshot returned by Summary().
//
// summary := stats.Summary()
// NewStats().Summary()
type StatsSummary struct {
Accepted uint64 `json:"accepted"`
Rejected uint64 `json:"rejected"`

View file

@ -5,10 +5,8 @@ import (
"time"
)
// Workers maintains per-worker aggregate stats. Workers are identified by name,
// derived from the miner's login fields per WorkersMode.
//
// workers := proxy.NewWorkers(proxy.WorkersByRigID, bus)
// workers := NewWorkers(WorkersByRigID, bus)
// records := workers.List()
type Workers struct {
mode WorkersMode
entries []WorkerRecord // ordered by first-seen (stable)
@ -18,9 +16,7 @@ type Workers struct {
mu sync.RWMutex
}
// WorkerRecord is the per-identity aggregate.
//
// hr60 := record.Hashrate(60)
// record.Hashrate(60)
type WorkerRecord struct {
Name string
LastIP string