fix(proxy): validate config and reload pools
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
b8cf8713c5
commit
7f44596858
6 changed files with 172 additions and 9 deletions
41
config_test.go
Normal file
41
config_test.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package proxy
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestConfig_Validate_Good(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Mode: "nicehash",
|
||||
Workers: WorkersByRigID,
|
||||
Bind: []BindAddr{{Host: "0.0.0.0", Port: 3333}},
|
||||
Pools: []PoolConfig{{URL: "pool.example:3333", Enabled: true}},
|
||||
}
|
||||
|
||||
if result := cfg.Validate(); !result.OK {
|
||||
t.Fatalf("expected valid config, got error: %v", result.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfig_Validate_Bad(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Workers: WorkersByRigID,
|
||||
Bind: []BindAddr{{Host: "0.0.0.0", Port: 3333}},
|
||||
Pools: []PoolConfig{{URL: "pool.example:3333", Enabled: true}},
|
||||
}
|
||||
|
||||
if result := cfg.Validate(); result.OK {
|
||||
t.Fatalf("expected missing mode to fail validation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfig_Validate_Ugly(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Mode: "nicehash",
|
||||
Workers: WorkersMode("unknown"),
|
||||
Bind: []BindAddr{{Host: "0.0.0.0", Port: 3333}},
|
||||
Pools: []PoolConfig{{URL: "", Enabled: true}},
|
||||
}
|
||||
|
||||
if result := cfg.Validate(); result.OK {
|
||||
t.Fatalf("expected invalid workers and empty pool url to fail validation")
|
||||
}
|
||||
}
|
||||
28
core_impl.go
28
core_impl.go
|
|
@ -59,10 +59,6 @@ func LoadConfig(path string) (*Config, Result) {
|
|||
if err := json.Unmarshal(data, cfg); err != nil {
|
||||
return nil, errorResult(err)
|
||||
}
|
||||
|
||||
if cfg.Mode == "" {
|
||||
cfg.Mode = "nicehash"
|
||||
}
|
||||
return cfg, cfg.Validate()
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +67,12 @@ func (c *Config) Validate() Result {
|
|||
if c == nil {
|
||||
return errorResult(errors.New("config is nil"))
|
||||
}
|
||||
if !isValidMode(c.Mode) {
|
||||
return errorResult(errors.New("mode must be \"nicehash\" or \"simple\""))
|
||||
}
|
||||
if !isValidWorkersMode(c.Workers) {
|
||||
return errorResult(errors.New("workers must be one of \"rig-id\", \"user\", \"password\", \"agent\", \"ip\", or \"false\""))
|
||||
}
|
||||
if len(c.Bind) == 0 {
|
||||
return errorResult(errors.New("bind list is empty"))
|
||||
}
|
||||
|
|
@ -85,6 +87,24 @@ func (c *Config) Validate() Result {
|
|||
return successResult()
|
||||
}
|
||||
|
||||
func isValidMode(mode string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(mode)) {
|
||||
case "nicehash", "simple":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isValidWorkersMode(mode WorkersMode) bool {
|
||||
switch mode {
|
||||
case WorkersByRigID, WorkersByUser, WorkersByPass, WorkersByAgent, WorkersByIP, WorkersDisabled:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// NewEventBus creates an empty synchronous event dispatcher.
|
||||
func NewEventBus() *EventBus {
|
||||
return &EventBus{listeners: make(map[EventType][]EventHandler)}
|
||||
|
|
|
|||
12
pool/impl.go
12
pool/impl.go
|
|
@ -338,7 +338,7 @@ func (s *FailoverStrategy) Connect() {
|
|||
}
|
||||
|
||||
func (s *FailoverStrategy) connectLocked(start int) {
|
||||
enabled := enabledPools(s.pools)
|
||||
enabled := enabledPools(s.currentPools())
|
||||
if len(enabled) == 0 {
|
||||
return
|
||||
}
|
||||
|
|
@ -368,6 +368,16 @@ func (s *FailoverStrategy) connectLocked(start int) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *FailoverStrategy) currentPools() []proxy.PoolConfig {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
if s.cfg != nil && len(s.cfg.Pools) > 0 {
|
||||
return s.cfg.Pools
|
||||
}
|
||||
return s.pools
|
||||
}
|
||||
|
||||
// Submit sends the share through the active client.
|
||||
func (s *FailoverStrategy) Submit(jobID, nonce, result, algo string) int64 {
|
||||
if s == nil || s.client == nil {
|
||||
|
|
|
|||
27
pool/impl_test.go
Normal file
27
pool/impl_test.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package pool
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"dappco.re/go/proxy"
|
||||
)
|
||||
|
||||
func TestFailoverStrategy_CurrentPools_Good(t *testing.T) {
|
||||
cfg := &proxy.Config{
|
||||
Mode: "nicehash",
|
||||
Workers: proxy.WorkersByRigID,
|
||||
Bind: []proxy.BindAddr{{Host: "127.0.0.1", Port: 3333}},
|
||||
Pools: []proxy.PoolConfig{{URL: "pool-a.example:3333", Enabled: true}},
|
||||
}
|
||||
strategy := NewFailoverStrategy(cfg.Pools, nil, cfg)
|
||||
|
||||
if got := len(strategy.currentPools()); got != 1 {
|
||||
t.Fatalf("expected 1 pool, got %d", got)
|
||||
}
|
||||
|
||||
cfg.Pools = []proxy.PoolConfig{{URL: "pool-b.example:4444", Enabled: true}}
|
||||
|
||||
if got := strategy.currentPools(); len(got) != 1 || got[0].URL != "pool-b.example:4444" {
|
||||
t.Fatalf("expected current pools to follow config reload, got %+v", got)
|
||||
}
|
||||
}
|
||||
58
reload_test.go
Normal file
58
reload_test.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package proxy
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestProxy_Reload_Good(t *testing.T) {
|
||||
original := &Config{
|
||||
Mode: "nicehash",
|
||||
Workers: WorkersByRigID,
|
||||
Bind: []BindAddr{{Host: "127.0.0.1", Port: 3333}},
|
||||
Pools: []PoolConfig{{URL: "pool-a.example:3333", Enabled: true}},
|
||||
}
|
||||
p := &Proxy{
|
||||
config: original,
|
||||
customDiff: NewCustomDiff(1),
|
||||
rateLimit: NewRateLimiter(RateLimit{}),
|
||||
}
|
||||
|
||||
updated := &Config{
|
||||
Mode: "simple",
|
||||
Workers: WorkersByUser,
|
||||
Bind: []BindAddr{{Host: "0.0.0.0", Port: 4444}},
|
||||
Pools: []PoolConfig{{URL: "pool-b.example:4444", Enabled: true}},
|
||||
CustomDiff: 50000,
|
||||
AccessPassword: "secret",
|
||||
CustomDiffStats: true,
|
||||
AlgoExtension: true,
|
||||
AccessLogFile: "/tmp/access.log",
|
||||
ReuseTimeout: 30,
|
||||
Retries: 5,
|
||||
RetryPause: 2,
|
||||
Watch: true,
|
||||
RateLimit: RateLimit{MaxConnectionsPerMinute: 10, BanDurationSeconds: 60},
|
||||
}
|
||||
|
||||
p.Reload(updated)
|
||||
|
||||
if p.config != original {
|
||||
t.Fatalf("expected reload to preserve the existing config pointer")
|
||||
}
|
||||
if got := p.config.Bind[0]; got.Host != "127.0.0.1" || got.Port != 3333 {
|
||||
t.Fatalf("expected bind addresses to remain unchanged, got %+v", got)
|
||||
}
|
||||
if p.config.Mode != "nicehash" {
|
||||
t.Fatalf("expected mode to remain unchanged, got %q", p.config.Mode)
|
||||
}
|
||||
if p.config.Workers != WorkersByRigID {
|
||||
t.Fatalf("expected workers mode to remain unchanged, got %q", p.config.Workers)
|
||||
}
|
||||
if got := p.config.Pools[0].URL; got != "pool-b.example:4444" {
|
||||
t.Fatalf("expected pools to reload, got %q", got)
|
||||
}
|
||||
if got := p.customDiff.globalDiff; got != 50000 {
|
||||
t.Fatalf("expected custom diff to reload, got %d", got)
|
||||
}
|
||||
if !p.rateLimit.IsActive() {
|
||||
t.Fatalf("expected rate limiter to be replaced with active configuration")
|
||||
}
|
||||
}
|
||||
|
|
@ -35,9 +35,6 @@ func New(cfg *Config) (*Proxy, Result) {
|
|||
if cfg == nil {
|
||||
return nil, errorResult(errors.New("config is nil"))
|
||||
}
|
||||
if cfg.Mode == "" {
|
||||
cfg.Mode = "nicehash"
|
||||
}
|
||||
if result := cfg.Validate(); !result.OK {
|
||||
return nil, result
|
||||
}
|
||||
|
|
@ -227,7 +224,17 @@ func (p *Proxy) Reload(cfg *Config) {
|
|||
if p == nil || cfg == nil {
|
||||
return
|
||||
}
|
||||
p.config = cfg
|
||||
if p.config == nil {
|
||||
p.config = cfg
|
||||
} else {
|
||||
preservedBind := append([]BindAddr(nil), p.config.Bind...)
|
||||
preservedMode := p.config.Mode
|
||||
preservedWorkers := p.config.Workers
|
||||
*p.config = *cfg
|
||||
p.config.Bind = preservedBind
|
||||
p.config.Mode = preservedMode
|
||||
p.config.Workers = preservedWorkers
|
||||
}
|
||||
if p.customDiff != nil {
|
||||
p.customDiff.globalDiff = cfg.CustomDiff
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue