diff --git a/config.go b/config.go index c7dd84e..0ac1023 100644 --- a/config.go +++ b/config.go @@ -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 ( diff --git a/events.go b/events.go index d31ffec..a662fa8 100644 --- a/events.go +++ b/events.go @@ -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 diff --git a/job.go b/job.go index fb6fe07..67367df 100644 --- a/job.go +++ b/job.go @@ -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 diff --git a/proxy.go b/proxy.go index e399796..c861fc1 100644 --- a/proxy.go +++ b/proxy.go @@ -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 diff --git a/server.go b/server.go index 140d69a..d2d9fe9 100644 --- a/server.go +++ b/server.go @@ -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 diff --git a/stats.go b/stats.go index b19558f..3e04406 100644 --- a/stats.go +++ b/stats.go @@ -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"` diff --git a/worker.go b/worker.go index 7f04e26..e3151ec 100644 --- a/worker.go +++ b/worker.go @@ -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