134 lines
3.1 KiB
Go
134 lines
3.1 KiB
Go
package pool
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"dappco.re/go/core/proxy"
|
|
)
|
|
|
|
// FailoverStrategy wraps an ordered slice of PoolConfig entries.
|
|
// It connects to the first enabled pool and fails over in order on error.
|
|
// On reconnect it always retries from the primary first.
|
|
//
|
|
// strategy := pool.NewFailoverStrategy(cfg.Pools, listener, cfg)
|
|
// strategy.Connect()
|
|
type FailoverStrategy struct {
|
|
pools []proxy.PoolConfig
|
|
current int
|
|
client *StratumClient
|
|
listener StratumListener
|
|
cfg *proxy.Config
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// StrategyFactory creates a new FailoverStrategy for a given StratumListener.
|
|
// Used by splitters to create per-mapper strategies without coupling to Config.
|
|
//
|
|
// factory := pool.NewStrategyFactory(cfg)
|
|
// strategy := factory(listener) // each mapper calls this
|
|
type StrategyFactory func(listener StratumListener) Strategy
|
|
|
|
// Strategy is the interface the splitters use to submit shares and check pool state.
|
|
type Strategy interface {
|
|
Connect()
|
|
Submit(jobID, nonce, result, algo string) int64
|
|
Disconnect()
|
|
IsActive() bool
|
|
}
|
|
|
|
// NewStrategyFactory captures the pool list and retry settings for later mapper creation.
|
|
//
|
|
// factory := pool.NewStrategyFactory(cfg)
|
|
func NewStrategyFactory(cfg *proxy.Config) StrategyFactory {
|
|
return func(listener StratumListener) Strategy {
|
|
if cfg == nil {
|
|
return NewFailoverStrategy(nil, listener, nil)
|
|
}
|
|
return NewFailoverStrategy(cfg.Pools, listener, cfg)
|
|
}
|
|
}
|
|
|
|
// NewFailoverStrategy stores the pool list and listener.
|
|
//
|
|
// strategy := pool.NewFailoverStrategy(cfg.Pools, listener, cfg)
|
|
func NewFailoverStrategy(pools []proxy.PoolConfig, listener StratumListener, cfg *proxy.Config) *FailoverStrategy {
|
|
return &FailoverStrategy{
|
|
pools: append([]proxy.PoolConfig(nil), pools...),
|
|
listener: listener,
|
|
cfg: cfg,
|
|
}
|
|
}
|
|
|
|
// Connect dials the current pool. On failure, advances to the next pool.
|
|
//
|
|
// strategy.Connect()
|
|
func (s *FailoverStrategy) Connect() {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
pools := s.pools
|
|
if s.cfg != nil {
|
|
pools = s.cfg.Pools
|
|
}
|
|
if len(pools) == 0 {
|
|
return
|
|
}
|
|
|
|
retries := 1
|
|
pause := time.Duration(0)
|
|
if s.cfg != nil {
|
|
if s.cfg.Retries > 0 {
|
|
retries = s.cfg.Retries
|
|
}
|
|
if s.cfg.RetryPause > 0 {
|
|
pause = time.Duration(s.cfg.RetryPause) * time.Second
|
|
}
|
|
}
|
|
|
|
for attempt := 0; attempt < retries; attempt++ {
|
|
for index, poolConfig := range pools {
|
|
if !poolConfig.Enabled {
|
|
continue
|
|
}
|
|
|
|
client := NewStratumClient(poolConfig, s.listener)
|
|
if errorValue := client.Connect(); errorValue == nil {
|
|
s.client = client
|
|
s.current = index
|
|
client.Login()
|
|
return
|
|
}
|
|
}
|
|
|
|
if pause > 0 && attempt < retries-1 {
|
|
time.Sleep(pause)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *FailoverStrategy) Submit(jobID string, nonce string, result string, algo string) int64 {
|
|
s.mu.Lock()
|
|
client := s.client
|
|
s.mu.Unlock()
|
|
if client == nil {
|
|
return 0
|
|
}
|
|
return client.Submit(jobID, nonce, result, algo)
|
|
}
|
|
|
|
func (s *FailoverStrategy) Disconnect() {
|
|
s.mu.Lock()
|
|
client := s.client
|
|
s.client = nil
|
|
s.mu.Unlock()
|
|
if client != nil {
|
|
client.Disconnect()
|
|
}
|
|
}
|
|
|
|
func (s *FailoverStrategy) IsActive() bool {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
return s.client != nil && s.client.active
|
|
}
|