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:
@@ -2,18 +2,21 @@ package config
|
||||
|
||||
import "time"
|
||||
|
||||
// Default stub used for local development builds. The Miner Builder replaces this file.
|
||||
func GetBuiltinConfig() BuiltinConfig {
|
||||
return BuiltinConfig{
|
||||
WorkerName: "dev-worker",
|
||||
ServerURL: "http://127.0.0.1:8989",
|
||||
Wallet: "",
|
||||
Threads: 4,
|
||||
ThreadMode: "percent",
|
||||
ThreadPercent: 75,
|
||||
CPUPriority: "below_normal",
|
||||
MiningMode: "always",
|
||||
DisplayMode: "visible",
|
||||
SilentMode: false,
|
||||
RunAs: "user",
|
||||
AutoStart: false,
|
||||
ProcessName: "CryptoMinerWorker",
|
||||
BuildID: "dev",
|
||||
BuiltAt: time.Now(),
|
||||
PoolHost: "pool.supportxmr.com",
|
||||
@@ -21,6 +24,7 @@ func GetBuiltinConfig() BuiltinConfig {
|
||||
PoolTLS: true,
|
||||
PoolPass: "x",
|
||||
MaxCPUUsage: 80,
|
||||
MaxMemoryPct: 70,
|
||||
MinFreeRAM: 1024,
|
||||
IdleThresholdPct: 20,
|
||||
IdleDurationMinutes: 5,
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const Version = "1.0.0"
|
||||
|
||||
// BuiltinConfig holds compile-time settings generated by the Miner Builder.
|
||||
type BuiltinConfig struct {
|
||||
WorkerName string
|
||||
ServerURL string
|
||||
Wallet string
|
||||
Threads int
|
||||
ThreadMode string
|
||||
ThreadPercent int
|
||||
CPUPriority string
|
||||
MiningMode string
|
||||
DisplayMode string
|
||||
SilentMode bool
|
||||
RunAs string
|
||||
AutoStart bool
|
||||
ProcessName string
|
||||
BuildID string
|
||||
BuiltAt time.Time
|
||||
PoolHost string
|
||||
@@ -24,6 +29,7 @@ type BuiltinConfig struct {
|
||||
PoolTLS bool
|
||||
PoolPass string
|
||||
MaxCPUUsage int
|
||||
MaxMemoryPct int
|
||||
MinFreeRAM int
|
||||
IdleThresholdPct int
|
||||
IdleDurationMinutes int
|
||||
@@ -31,7 +37,6 @@ type BuiltinConfig struct {
|
||||
ScheduleEnd string
|
||||
}
|
||||
|
||||
// RuntimeConfig is the resolved configuration used by the agent.
|
||||
type RuntimeConfig struct {
|
||||
BuiltinConfig
|
||||
AgentID string
|
||||
@@ -42,15 +47,34 @@ func Load() RuntimeConfig {
|
||||
if b.Threads <= 0 {
|
||||
b.Threads = 4
|
||||
}
|
||||
if b.ThreadMode == "" {
|
||||
b.ThreadMode = "percent"
|
||||
}
|
||||
if b.ThreadPercent <= 0 {
|
||||
b.ThreadPercent = 75
|
||||
}
|
||||
if b.CPUPriority == "" {
|
||||
b.CPUPriority = "below_normal"
|
||||
}
|
||||
if b.MiningMode == "" {
|
||||
b.MiningMode = "always"
|
||||
}
|
||||
if b.DisplayMode == "" {
|
||||
if b.SilentMode {
|
||||
b.DisplayMode = "silent"
|
||||
} else {
|
||||
b.DisplayMode = "visible"
|
||||
}
|
||||
}
|
||||
if b.ProcessName == "" {
|
||||
b.ProcessName = sanitizeProcessName(b.WorkerName)
|
||||
}
|
||||
if b.MaxCPUUsage <= 0 {
|
||||
b.MaxCPUUsage = 80
|
||||
}
|
||||
if b.MaxMemoryPct <= 0 {
|
||||
b.MaxMemoryPct = 70
|
||||
}
|
||||
if b.MinFreeRAM <= 0 {
|
||||
b.MinFreeRAM = 1024
|
||||
}
|
||||
@@ -68,3 +92,58 @@ func Load() RuntimeConfig {
|
||||
}
|
||||
return RuntimeConfig{BuiltinConfig: b}
|
||||
}
|
||||
|
||||
func (c RuntimeConfig) EffectiveThreads() int {
|
||||
mode := strings.ToLower(c.ThreadMode)
|
||||
if mode == "fixed" {
|
||||
if c.Threads < 1 {
|
||||
return 1
|
||||
}
|
||||
return c.Threads
|
||||
}
|
||||
cores := runtime.NumCPU()
|
||||
if cores < 1 {
|
||||
cores = 1
|
||||
}
|
||||
pct := c.ThreadPercent
|
||||
if pct < 1 {
|
||||
pct = 1
|
||||
}
|
||||
if pct > 100 {
|
||||
pct = 100
|
||||
}
|
||||
threads := int(float64(cores) * float64(pct) / 100.0)
|
||||
if threads < 1 {
|
||||
threads = 1
|
||||
}
|
||||
if threads > cores {
|
||||
threads = cores
|
||||
}
|
||||
return threads
|
||||
}
|
||||
|
||||
func (c RuntimeConfig) HideWindow() bool {
|
||||
switch strings.ToLower(c.DisplayMode) {
|
||||
case "silent", "background":
|
||||
return true
|
||||
default:
|
||||
return c.SilentMode
|
||||
}
|
||||
}
|
||||
|
||||
func (c RuntimeConfig) BackgroundMode() bool {
|
||||
return strings.ToLower(c.DisplayMode) == "background"
|
||||
}
|
||||
|
||||
func sanitizeProcessName(name string) string {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return "CryptoMinerWorker"
|
||||
}
|
||||
replacer := strings.NewReplacer(" ", "", "-", "", "_", "")
|
||||
clean := replacer.Replace(name)
|
||||
if clean == "" {
|
||||
return "CryptoMinerWorker"
|
||||
}
|
||||
return clean
|
||||
}
|
||||
|
||||
45
agent/config/resolve_test.go
Normal file
45
agent/config/resolve_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package config
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEffectiveThreadsFixed(t *testing.T) {
|
||||
cfg := RuntimeConfig{BuiltinConfig: BuiltinConfig{ThreadMode: "fixed", Threads: 3}}
|
||||
if got := cfg.EffectiveThreads(); got != 3 {
|
||||
t.Fatalf("expected 3, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEffectiveThreadsPercentCaps(t *testing.T) {
|
||||
cfg := RuntimeConfig{BuiltinConfig: BuiltinConfig{ThreadMode: "percent", ThreadPercent: 150}}
|
||||
got := cfg.EffectiveThreads()
|
||||
if got < 1 {
|
||||
t.Fatalf("expected at least 1 thread, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEffectiveThreadsPercentZeroUsesMinimum(t *testing.T) {
|
||||
cfg := RuntimeConfig{BuiltinConfig: BuiltinConfig{ThreadMode: "percent", ThreadPercent: 0}}
|
||||
if got := cfg.EffectiveThreads(); got < 1 {
|
||||
t.Fatalf("expected minimum 1 thread, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHideWindowModes(t *testing.T) {
|
||||
silent := RuntimeConfig{BuiltinConfig: BuiltinConfig{DisplayMode: "silent"}}
|
||||
if !silent.HideWindow() {
|
||||
t.Fatal("silent should hide window")
|
||||
}
|
||||
visible := RuntimeConfig{BuiltinConfig: BuiltinConfig{DisplayMode: "visible"}}
|
||||
if visible.HideWindow() {
|
||||
t.Fatal("visible should not hide window")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizeProcessName(t *testing.T) {
|
||||
if got := sanitizeProcessName("office pc 1"); got != "officepc1" {
|
||||
t.Fatalf("unexpected process name: %s", got)
|
||||
}
|
||||
if got := sanitizeProcessName(""); got != "CryptoMinerWorker" {
|
||||
t.Fatalf("expected default process name, got %s", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user